home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / BASIC / 3766.ZIP / BASWIZ.ZIP / BASWIZ.DOC < prev    next >
Text File  |  1993-07-05  |  161KB  |  4,003 lines

  1.      BasWiz  Copyright (c) 1990-1993  Thomas G. Hanlin III
  2.      =---------------------------------------------------=
  3.             The BASIC Wizard's Library, version 2.0
  4.  
  5.  
  6.  
  7. Use of LibWiz or LibMatic is strongly recommended for creating
  8. the BasWiz library, due to the number of routines involved.
  9.  
  10. This is BasWiz, a general-purpose library with hundreds of
  11. routines for use with Microsoft BASIC compilers: QuickBasic,
  12. Bascom/PDS, and Visual BASIC for DOS.
  13.  
  14. The BasWiz collection is copyrighted. It may be distributed only
  15. under the following conditions:
  16.  
  17.    All BasWiz files must be distributed together as a unit.
  18.    No files may be altered, added, or deleted from this unit.
  19.  
  20. BasWiz is not free software. If you find this evaluation copy
  21. suited to your needs, send in your registration. The complete
  22. registered edition includes assembly language source code, a
  23. sampler of other quality software, and an unlimited license to
  24. distribute BasWiz routines as part of your compiled programs.
  25.  
  26. You use BasWiz entirely at your own risk. It works for me on the
  27. computers I've tried it on, of course. I can't guarantee it will
  28. do the same for you. If you have trouble using BasWiz, tell me
  29. about it, and I'll see what I can do. The WHERE.BBS file gives
  30. mail and email addresses at which you can find me.
  31.  
  32.  
  33.  
  34. To create a BasWiz library using LibWiz, you will need a
  35. complete set of .OBJ files for all BasWiz routines. Create a
  36. fresh subdirectory and extract the BASIC source code from the
  37. BW$BAS archive. Compile them using a DOS command like so:
  38.  
  39.    FOR %x IN (*.BAS) DO BC %x /o;
  40.  
  41. Add the /FS switch (before the /o) if you wish to use far
  42. strings with the PDS compiler. This is required for using BasWiz
  43. in the QBX editor/environment.
  44.  
  45. Extract the .OBJ files from BW$MAIN.LIB into the same location,
  46. using the UNLIB utility that comes with LibWiz.
  47.  
  48. Now you must extract the string routines by using UNLIB on the
  49. appropriate string library: BW$NEAR.LIB for near strings or
  50. BW$FAR for far strings. For QuickBasic, use near strings. For
  51. Visual Basic, use far strings. For PDS, choose one or the other
  52. (use far strings if you use the QBX editor/environment).
  53.  
  54. After these three steps-- compiling the BASIC files with your
  55. compiler, extracting the main .OBJ files, and extracting the
  56. appropriate string .OBJ files-- you have a complete set of .OBJs
  57. for BasWiz. Use LibWiz to create a custom subset of BasWiz
  58. that's tailored to your needs.
  59.  
  60.                       Table of Contents                 page 2
  61.  
  62.  
  63.  
  64.  Overview and Legal Info ................................... 1
  65.  
  66.  BCD Math .................................................. 3
  67.  
  68.  Expression Evaluator ...................................... 7
  69.  
  70.  Extensions to BASIC's math ................................ 8
  71.  
  72.  Far Strings .............................................. 11
  73.  
  74.  File Handling ............................................ 13
  75.  
  76.  Fractions ................................................ 21
  77.  
  78.  Graphics
  79.     General Routines ...................................... 22
  80.     VESA Info Routines .................................... 32
  81.     Text-mode Routines .................................... 34
  82.     Dual Monitor Routines ................................. 35
  83.     Printer Routines ...................................... 36
  84.     A Little Geometry ..................................... 37
  85.     Equations, Etc ........................................ 41
  86.  
  87.  Memory Management and Pointers ........................... 44
  88.  
  89.  Quick Time (millisecond timer) ........................... 48
  90.  
  91.  Telecommunications ....................................... 50
  92.  
  93.  Virtual Windowing System ................................. 56
  94.  
  95.  Other Routines ........................................... 70
  96.  
  97.  Miscellaneous Notes ...................................... 71
  98.  
  99.  Error Codes .............................................. 74
  100.  
  101.  Troubleshooting .......................................... 76
  102.  
  103.  History & Philosophy ..................................... 79
  104.  
  105.  Using BasWiz with P.D.Q. or QBTiny ....................... 81
  106.  
  107.  Credits .................................................. 82
  108.  
  109.                           BCD Math                      page 3
  110.  
  111.  
  112.  
  113. Some of you may not have heard of BCD math, or at least not have
  114. more than a passing acquaintance with the subject. BCD (short
  115. for Binary-Coded Decimal) is a way of encoding numbers. It
  116. differs from the normal method of handling numbers in several
  117. respects. On the down side, BCD math is much slower than normal
  118. math and the numbers take up more memory. However, the benefits
  119. may far outweigh these disadvantages, depending on your
  120. application: BCD math is absolutely precise within your desired
  121. specifications, and you can make a BCD number as large as you
  122. need. If your applications don't require great range or
  123. precision out of numbers, normal BASIC math is probably the best
  124. choice. For scientific applications, accounting, engineering and
  125. other demanding tasks, though, BCD may be just the thing you
  126. need.
  127.  
  128. The BCD math routines provided by BasWiz allow numbers of up to
  129. 255 digits long (the sign counts as a digit, but the decimal
  130. point doesn't). You may set the decimal point to any position
  131. you like, as long as there is at least one digit position to the
  132. left of the decimal.
  133.  
  134. Since QuickBasic doesn't support BCD numbers directly, we store
  135. the BCD numbers in strings. The results are not in text format
  136. and won't mean much if displayed. A conversion routine allows
  137. you to change a BCD number to a text string in any of a variety
  138. of formats.
  139.  
  140. Note that the BCD math handler doesn't yet track
  141. overflow/underflow error conditions. If you anticipate that this
  142. may be a problem, it would be a good idea to screen your input
  143. or to make the BCD range large enough to avoid these errors.
  144.  
  145. Let's start off by examining the routine which allows you to set
  146. the BCD range:
  147.  
  148.    BCDSetSize LeftDigits%, RightDigits%
  149.  
  150. The parameters specify the maximum number of digits to the left
  151. and to the right of the decimal point. There must be at least
  152. one digit on the left, and the total number of digits must be
  153. less than 255. The BCD strings will have a length that's one
  154. larger than the total number of digits, to account for the sign
  155. of the number. The decimal point is implicit and doesn't take up
  156. any extra space.
  157.  
  158. It is assumed that you will only use one size of BCD number in
  159. your program-- there are no provisions for handling mixed-length
  160. BCD numbers. Of course, you could manage that yourself with a
  161. little extra work, if it seems like a useful capability. If you
  162. don't use BCDSetSize, the default size of the BCD numbers will
  163. be 32 (20 to the left, 11 to the right, 1 for the sign).
  164.  
  165.                           BCD Math                      page 4
  166.  
  167.  
  168.  
  169. You can get the current size settings as well:
  170.  
  171.    BCDGetSize LeftDigits%, RightDigits%
  172.  
  173. Of course, before doing any BCD calculations, you must have some
  174. BCD numbers! The BCDSet routine takes a number in text string
  175. form and converts it to BCD:
  176.  
  177.    TextSt$ = "1234567890.50"
  178.    Nr$ = BCDSet$(TextSt$)
  179.  
  180. If your numbers are stored as actual numbers, you can convert
  181. them to a text string with BASIC's STR$ function, then to BCD.
  182. Leading spaces are ignored:
  183.  
  184.    Nr$ = BCDSet$(STR$(AnyNum#))
  185.  
  186. BCD numbers can also be converted back to text strings, of
  187. course. You may specify how many digits to the right of the
  188. decimal to keep (the number will be truncated, not rounded). If
  189. the RightDigits% is positive, trailing zeros will be kept; if
  190. negative, trailing zeros will be removed. There are also various
  191. formatting options which may be used. Here's how it works:
  192.  
  193.    TextSt$ = BCDFormat$(Nr$, HowToFormat%, RightDigits%)
  194.  
  195. The HowToFormat% value may be any combination of the following
  196. (just add the numbers of the desired formats together):
  197.  
  198.    0   plain number
  199.    1   use commas to separate thousands, etc
  200.    2   start number with a dollar sign
  201.    4   put the sign on the right side of the number
  202.    8   use a plus sign if the number is not negative
  203.  
  204.                           BCD Math                      page 5
  205.  
  206.  
  207.  
  208. The BCD math functions are pretty much self-explanatory, so I'll
  209. keep the descriptions brief. Here are the single-parameter
  210. functions:
  211.  
  212.    Result$ = BCDAbs$(Nr$)       ' absolute value
  213.    Result$ = BCDCos$(Nr$)       ' cosine function
  214.    Result$ = BCDCot$(Nr$)       ' cotangent function
  215.    Result$ = BCDCsc$(Nr$)       ' cosecant function
  216.    Result$ = BCDDeg2Rad$(Nr$)   ' convert degrees to radians
  217.    e$ = BCDe$                   ' the constant "e"
  218.    Result$ = BCDFact$(N%)       ' factorial
  219.    Result$ = BCDFrac$(Nr$)      ' return the fractional part
  220.    Result$ = BCDInt$(Nr$)       ' return the integer part
  221.    Result$ = BCDNeg$(Nr$)       ' negate a number
  222.    pi$ = BCDpi$                 ' the constant "pi"
  223.    Result$ = BCDRad2Deg$(Nr$)   ' convert radians to degrees
  224.    Result$ = BCDSec$(Nr$)       ' secant function
  225.    Result% = BCDSgn%(Nr$)       ' signum function
  226.    Result$ = BCDSin$(Nr$)       ' sine function
  227.    Result$ = BCDSqr$(Nr$)       ' square root
  228.    Result$ = BCDTan$(Nr$)       ' tangent function
  229.  
  230. Notes on the single-parameter functions:
  231.  
  232.   The signum function returns an integer based on the sign of
  233.   the BCD number:
  234.  
  235.      -1   if the BCD number is negative
  236.       0   if the BCD number is zero
  237.       1   if the BCD number is positive
  238.  
  239.   BCDpi$ is accurate to the maximum level afforded by the BCD
  240.   functions. BCDe$ is accurate to as many as 115 decimal places.
  241.   The actual accuracy, of course, depends on the size of BCD
  242.   numbers you've chosen.
  243.  
  244.   The trigonometric functions (cos, sin, tan, sec, csc, cot)
  245.   expect angles in radians. BCDDeg2Rad and BCDRad2Deg will allow
  246.   you to convert back and forth between radians and degrees.
  247.  
  248.                           BCD Math                      page 6
  249.  
  250.  
  251.  
  252. Here is a list of the two-parameter functions:
  253.  
  254.  
  255.    Result$ = BCDAdd$(Nr1$, Nr2$)      ' Nr1 + Nr2
  256.  
  257.    Result$ = BCDSub$(Nr1$, Nr2$)      ' Nr1 - Nr2
  258.  
  259.    Result$ = BCDMul$(Nr1$, Nr2$)      ' Nr1 * Nr2
  260.  
  261.    Result$ = BCDDiv$(Nr1$, Nr2$)      ' Nr1 / Nr2
  262.  
  263.    Result$ = BCDPower$(Nr$, Power%)   ' Nr ^ Power
  264.  
  265.    Result% = BCDCompare%(Nr1$, Nr2$)  ' compare two numbers
  266.  
  267. The comparison function returns an integer which reflects how
  268. the two numbers compare to each other:
  269.  
  270.    -1   Nr1 < Nr2
  271.     0   Nr1 = Nr2
  272.     1   Nr1 > Nr2
  273.  
  274.                     Expression Evaluator                page 7
  275.  
  276.  
  277.  
  278. The expression evaluator allows you to find the result of an
  279. expression contained in a string. Normal algebraic precedence is
  280. used, e.g. 4+3*5 evaluates to 19. The usual numeric operators
  281. (*, /, +, -, ^) are supported (multiply, divide, add, subtract,
  282. and raise to a power). Use of negative numbers is just fine, of
  283. course. Parentheses for overriding the default order of
  284. operations are also supported.
  285.  
  286. You may use either double asterisk ("**") or caret ("^") symbols
  287. to indicate exponentiation.
  288.  
  289. The constant PI is recognized, as are the following functions:
  290.    ABS    absolute value        INT    integer
  291.    ACOS   inverse cosine        LOG    natural log
  292.    ASIN   inverse sine          SIN    sine
  293.    ATAN   inverse tangent       SQR    square root
  294.    COS    cosine                TAN    tangent
  295.    FRAC   fraction
  296.  
  297. Trig functions expect angles in radians.
  298.  
  299. To evaluate an expression, you pass it to the evaluator as a
  300. string. You will get back either an error code or a single-
  301. precision result. Try this example to see how the expression
  302. evaluator works:
  303.  
  304.    REM $INCLUDE: 'BASWIZ.BI'
  305.    DO
  306.       INPUT "Expression? "; Expr$
  307.       IF LEN(Expr$) THEN
  308.          Evaluate Expr$, Result!, ErrCode%
  309.          IF ErrCode% THEN
  310.             PRINT "Invalid expression.  Error = "; ErrCode%
  311.          ELSE
  312.             PRINT "Result: "; Result!
  313.          END IF
  314.       END IF
  315.    LOOP WHILE LEN(Expr$)
  316.    END
  317.  
  318. An expression evaluator adds convenience to any program that
  319. needs to accept numbers. Why make someone reach for a calculator
  320. when number crunching is what a computer does best?
  321.  
  322.                  Extensions to BASIC's math             page 8
  323.  
  324.  
  325.  
  326. For the most part, the math routines in this library is designed
  327. to provide alternatives to the math routines that are built into
  328. BASIC. Still, BASIC's own math support is quite adequate for
  329. many purposes, so there's no sense in ignoring it. Here are some
  330. functions which improve on BASIC's math. I'll list the single-
  331. precision functions on this page, and double-precision on the
  332. next.
  333.  
  334.    Result! = ArcCosHS!(Nr!)    ' inverse hyperbolic cosine
  335.    Result! = ArcCosS!(Nr!)     ' inverse cosine (1 >= Nr >= -1)
  336.    Result! = ArcCotS!(Nr!)     ' inverse cotangent
  337.    Result! = ArcCotSH!(Nr!)    ' inverse hyperbolic cotangent
  338.    Result! = ArcCscHS!(Nr!)    ' inverse hyperbolic cosecant
  339.    Result! = ArcCscS!(Nr!)     ' inverse cosecant
  340.    Result! = ArcSecHS!(Nr!)    ' inverse hyperbolic secant
  341.    Result! = ArcSecS!(Nr!)     ' inverse secant
  342.    Result! = ArcSinHS!(Nr!)    ' inverse hyperbolic sine
  343.    Result! = ArcSinS!(Nr!)     ' inverse sine (1 >= Nr >= -1)
  344.    Result! = ArcTanHS!(Nr!)    ' inverse hyperbolic tangent
  345.    Result! = Cent2Fahr!(Nr!)   ' centigrade to Fahrenheit
  346.    Result! = CosHS!(Nr!)       ' hyperbolic cosine
  347.    Result! = CotHS!(Nr!)       ' hyperbolic cotangent
  348.    Result! = CotS!(Nr!)        ' cotangent
  349.    Result! = CscHS!(Nr!)       ' hyperbolic cosecant
  350.    Result! = CscS!(Nr!)        ' cosecant
  351.    Result! = Deg2RadS!(Nr!)    ' convert degrees to radians
  352.    e! = eS!                    ' the constant "e"
  353.    Result! = ErfS!(Nr!)        ' error function
  354.    Result! = FactS!(Nr%)       ' factorial
  355.    Result! = Fahr2Cent!(Nr!)   ' Fahrenheit to centigrade
  356.    Result! = Kg2Pound!(Nr!)    ' convert kilograms to pounds
  357.    Pi! = PiS!                  ' the constant "pi"
  358.    Result! = Pound2Kg!(Nr!)    ' convert pounds to kilograms
  359.    Result! = Rad2DegS!(Nr!)    ' convert radians to degrees
  360.    Result! = SecHS!(Nr!)       ' hyperbolic secant
  361.    Result! = SecS!(Nr!)        ' secant
  362.    Result! = SinHS!(Nr!)       ' hyperbolic sine
  363.    Result! = TanHS!(Nr!)       ' hyperbolic tangent
  364.  
  365.                  Extensions to BASIC's math             page 9
  366.  
  367.  
  368.  
  369.    Result# = ArcCosD#(Nr#)     ' inverse cosine (1 >= Nr >= -1)
  370.    Result# = ArcCosHD#(Nr#)    ' inverse hyperbolic cosine
  371.    Result# = ArcCotD#(Nr#)     ' inverse cotangent
  372.    Result# = ArcCotHD#(Nr#)    ' inverse hyperbolic cotangent
  373.    Result# = ArcCscD#(Nr#)     ' inverse cosecant
  374.    Result# = ArcCscHD#(Nr#)    ' inverse hyperbolic cosecant
  375.    Result# = ArcSecD#(Nr#)     ' inverse secant
  376.    Result# = ArcSecHD#(Nr#)    ' inverse hyperbolic secant
  377.    Result# = ArcSinD#(Nr#)     ' inverse sine (1 >= Nr >= -1)
  378.    Result# = ArcSinHD#(Nr#)    ' inverse hyperbolic sine
  379.    Result# = ArcTanHD#(Nr#)    ' inverse hyperbolic tangent
  380.    Result# = CosHD#(Nr#)       ' hyperbolic cosine
  381.    Result# = CotD#(Nr#)        ' cotangent
  382.    Result# = CotHD#(Nr#)       ' hyperbolic cotangent
  383.    Result# = CscD#(Nr#)        ' cosecant
  384.    Result# = CscHD#(Nr#)       ' hyperbolic cosecant
  385.    Result# = Deg2RadD#(Nr#)    ' convert degrees to radians
  386.    e# = eD#                    ' the constant "e"
  387.    Result# = ErfD#(Nr#)        ' error function
  388.    Result# = FactD#(Nr%)       ' factorial
  389.    Pi# = PiD#                  ' the constant "pi"
  390.    Result# = Rad2DegD#(Nr#)    ' convert radians to degrees
  391.    Result# = SecD#(Nr#)        ' secant
  392.    Result# = SecHD#(Nr#)       ' hyperbolic secant
  393.    Result# = SinHD#(Nr#)       ' hyperbolic sine
  394.    Result# = TanHD#(Nr#)       ' hyperbolic tangent
  395.  
  396.                  Extensions to BASIC's math            page 10
  397.  
  398.  
  399.  
  400.    Result% = GCDI%(Nr1%, Nr2%)  ' greatest common denominator
  401.    Result% = Power2I%(Nr%)      ' raise 2 to a specified power
  402.    Result% = ROLI%(Nr%, Count%) ' bit-rotate left
  403.    Result% = RORI%(Nr%, Count%) ' bit-rotate right
  404.    Result% = SHLI%(Nr%, Count%) ' bit-shift left
  405.    Result% = SHRI%(Nr%, Count%) ' bit-shift right
  406.    Result% = VALI%(St$)         ' integer VAL function
  407.  
  408.    Result& = GCDL&(Nr1&, Nr2&)  ' greatest common denominator
  409.    Result& = Power2L&(Nr%)      ' raise 2 to a specified power
  410.  
  411.  
  412.  
  413. Like BASIC's trig functions, these trig functions expect the
  414. angle to be in radians. Conversion functions are provided in
  415. case you prefer degrees.
  416.  
  417. Note that there is no ArcTanS! or ArcTanD# function for the
  418. simple reason that BASIC supplies an ATN function.
  419.  
  420. Constants are expressed to the maximum precision available.
  421.  
  422. The Power2I% and Power2L& functions are vastly quicker than the
  423. equivalent BASIC formulas. If powers of two are useful to you,
  424. try these functions!
  425.  
  426.  
  427.  
  428. If you are not familiar with variable postfix symbols, here's a
  429. brief summary:
  430.  
  431.   Symbol   Meaning             Range (very approximate)
  432.   ------   --------            ------------------------
  433.     %      integer             +- 32767
  434.     &      long integer        +- 2 * 10^9
  435.     !      single precision    +- 1 * 10^38   (7-digit prec.)
  436.     #      double precision    +- 1 * 10^308  (15-digit prec.)
  437.     $      string              [0 to 32767 characters]
  438.  
  439. See your BASIC manual or QuickBasic's online help for further
  440. details.
  441.  
  442.                          Far Strings                   page 11
  443.  
  444.  
  445.  
  446. One of the best things about BASIC is its support for
  447. variable-length strings. Few other languages support such
  448. dynamically-allocated strings and they're a terrifically
  449. efficient way of using memory. At least, they would be, except
  450. for one minor limitation... in every version of QuickBasic and
  451. BASCOM (except for the new and expensive BASCOM 7.0
  452. "Professional Development System"), string space is limited to a
  453. mere 50K-60K bytes. As if this weren't trouble enough, this
  454. space is also shared with a number of other things. Running out
  455. of string space is a common and painful problem.
  456.  
  457. Anyway, it used to be. The BasWiz library comes with an
  458. assortment of routines and functions which allow you to keep
  459. variable-length strings outside of BASIC's tiny string area.
  460. Currently, you may have up to 65,535 far strings of up to 255
  461. characters each, subject to available memory. Either normal
  462. system memory or expanded memory may be used. Extended memory
  463. can also be used if you have an XMS driver (such as HIMEM.SYS)
  464. installed.
  465.  
  466. Using far strings works almost the same way as using normal
  467. strings. Rather than referring to a far string with a string
  468. variable name, however, you refer to it with an integer variable
  469. called a "handle". To create a new far string, you use a handle
  470. of zero. A new handle will be returned to you which will
  471. identify that string for future reference.
  472.  
  473. Before you use any far strings, you must initialize the far
  474. string handler. When you are done using far strings, you must
  475. terminate the far string handler. Normally, each of these
  476. actions will take place only once in your program: you
  477. initialize at the beginning and terminate at the end.
  478.  
  479. NOTE: The BasWiz far string handler does not support PDS or
  480. VB/DOS far strings! If you are using Microsoft far strings, you
  481. can't use BasWiz far strings.
  482.  
  483.                          Far Strings                   page 12
  484.  
  485.  
  486.  
  487. A working example of far string use is provided in FDEMO.BAS.
  488. Somewhat simplified code is given below as an overview.
  489.  
  490.    REM $INCLUDE: 'BASWIZ.BI'
  491.    DIM Text%(1 TO 5000)           ' array for string handles
  492.    FSInit 0                       ' init far string handler
  493.    TextLines = 0
  494.    OPEN "ANYFILE.TXT" FOR INPUT AS #1
  495.    DO UNTIL EOF(1)
  496.       LINE INPUT#1, TextRow$
  497.       Handle% = 0                 ' zero to create new string
  498.       FSSet Handle%, TextRow$     ' set far string
  499.       TextLines% = TextLines% + 1
  500.       Text(TextLines%) = Handle%  ' save far string handle
  501.    LOOP
  502.    CLOSE
  503.    FOR Row% = 1 TO TextLines%
  504.       PRINT FSGet$(Text%(Row%))   ' display a far string
  505.    NEXT
  506.    FSDone                         ' close far string handler
  507.    END
  508.  
  509. If you wanted to change an existing far string, you would
  510. specify its existing handle for FSSet. The handle of zero is
  511. used only to create new far strings, rather in the manner of
  512. using a new variable for the first time.
  513.  
  514. Note the 0 after the FSInit call. That specifies that main
  515. system memory is to be used. If you would prefer to use EMS, use
  516. a 1. If you specify EMS and none is available, BasWiz will fall
  517. back to conventional memory.
  518.  
  519.                         File Handling                  page 13
  520.  
  521.  
  522.  
  523. The file handling capabilities of BASIC were improved quite a
  524. bit as of QuickBasic 4.0. A binary mode was added and it became
  525. possible to use structured (TYPE) variables instead of the
  526. awkward FIELD-based random access handling. Even today, however,
  527. BASIC file handling is inefficient for many tasks. It requires
  528. error trapping to avoid problems like open floppy drive doors
  529. and cannot transfer information in large quantities at a time.
  530.  
  531. The BasWiz routines provide additional flexibility and power.
  532. They allow you to access files at as low or high a level as you
  533. wish. Here are some of the features of BasWiz file handling:
  534.  
  535.   - File sharing is automatically used if the DOS version is
  536.     high enough, (DOS 3.0 or later) providing effortless
  537.     network compatibility.
  538.   - Critical errors, like other errors, are detected at any
  539.     point you find convenient via a single function call.
  540.   - Optional input buffers speed up reading from files.
  541.   - Up to 32K of data may be read or written at one time.
  542.   - Files can be flushed to disk to avoid loss due to power
  543.     outages, etc.
  544.  
  545. Files are not considered to be strongly moded by BasWiz,
  546. although there are a few limitations on how you can deal with
  547. text files as opposed to other kinds of files. Reads and writes
  548. normally take place sequentially, like the INPUT and OUTPUT
  549. modes allowed by BASIC. However, you can also do random access
  550. by moving the file pointer to anywhere in the file, just as with
  551. the RANDOM and BINARY modes allowed by BASIC. These routines
  552. place no arbitrary limitations on the programmer.
  553.  
  554. As with BASIC, files are referred to by a number after they are
  555. opened for access. Unlike BASIC, the number is returned to you
  556. when the file is successfully opened, rather than being
  557. specified by you when you open the file. This means that you
  558. never have to worry about a file number already being in use.
  559. We'll refer to the file number as a "file handle" from now on.
  560.  
  561.                         File Handling                  page 14
  562.  
  563.  
  564.  
  565. Before doing anything else, you must initialize the file
  566. handling routines. This is typically done only once, at the
  567. beginning of your program. The FInit routine needs to know the
  568. number of files you want to deal with. This can be up to 15
  569. files, or possibly up to 50 if you are using DOS 3.3 or higher.
  570.  
  571.    FInit MaxFiles%, ErrCode%
  572.  
  573. A file is opened for access like so:
  574.  
  575.    FOpen File$, FMode$, BufferLen%, Handle%, ErrCode%
  576.  
  577. You pass the File$, FMode$, and BufferLen%. The Handle% and
  578. ErrCode% are returned to you. The BufferLen% valueis the length
  579. of the buffer desired for input. This must be zero if you want
  580. to write to the file. The filename is passed in File$, naturally
  581. enough. There is a choice of various modes for FMode$ and these
  582. can be combined to some extent:
  583.  
  584.    A   Append to file      used to add to an existing file
  585.    C   Create file         creates a new file
  586.    R   Read access         allows reading (input) from a file
  587.    T   Text mode file      allows text-mode input from a file
  588.    W   Write access        allows writing (output) to a file
  589.  
  590. For the most part, the combinations are self-explanatory. For
  591. instance, it would be reasonable to open a file for read and
  592. write, for create and write, for append and write, or for read
  593. and text. Text files always require a buffer. If you request
  594. text access without specifying a buffer, a buffer of 512 bytes
  595. will be provided for you. If you request "create" access without
  596. additional parameters, the file will be opened for write by
  597. default.
  598.  
  599. You may not use a buffer if you want to write to a file. This
  600. includes text files, which always use a buffer, as well as
  601. binary files. This is an artificial limitation which may change
  602. in a future version of BasWiz. It exists now to reduce the
  603. internal complexity of the routines which write to the file, so
  604. that they do not have to account for any buffering as well as
  605. the current file pointer. However, writing may be done to a
  606. text-type file if the file was not opened in text mode. We'll
  607. see how that works presently.
  608.  
  609. When you are done using a particular file, you can close it,
  610. just as in ordinary BASIC:
  611.  
  612.    FClose Handle%
  613.  
  614. Before your program ends, you should terminate the file handler.
  615. This will close any open files as well as concluding use of the
  616. file routines:
  617.  
  618.    FDone
  619.  
  620.                         File Handling                  page 15
  621.  
  622.  
  623.  
  624. That covers the basic set-up routines: initialize, open, close,
  625. and terminate. Of more interest are the routines which actually
  626. deal with the file itself. These provide assorted read/write
  627. services, the ability to get or set the file read/write pointer,
  628. size, time, and date, and the ability to get or set the error
  629. code for a specific file, among other things. Let's take a look
  630. at the error handler first.
  631.  
  632. The FInit and FOpen routines return an error code directly,
  633. since you need to know immediately if these have failed. The
  634. other file routines do not return a direct error code, however.
  635. In order to discover whether an error has occurred, you use the
  636. FGetError% function. This will return an error of zero if there
  637. was no error, or a specific error code (listed at the end of
  638. this manual) if some problem occurred. The error code will
  639. remain the same until you reset it using FError. The FError
  640. service also allows you to test your error handler by forcing
  641. specific error codes even when everything is fine.
  642.  
  643.    PRINT "Error code: "; FGetError%(Handle%)
  644.    FError Handle%, 0         ' clear the error code
  645.  
  646. It is recommended that you check for errors after any file
  647. routine is used if there is a chance that your program will be
  648. executed on a floppy disk. These are particularly prone to user
  649. errors (like leaving the drive door open) or running out of
  650. space. If your program will only run on a hard drive, you may
  651. not need to check as frequently. It's your choice. Note that the
  652. error code is not cleared automatically-- use FError to reset
  653. the error code to zero if you determine that it wasn't a serious
  654. error.
  655.  
  656. Down to the nitty-gritty... we've seen how to open and close a
  657. file, how to check operations for errors, and so forth. So how
  658. do we actually manipulate the file? There are assorted
  659. alternatives, depending on how you want to deal with the file:
  660. text reads, text writes, byte-oriented reads and writes, and
  661. block reads and writes, not to mention handling the time, date,
  662. size, and read/write pointer. We'll start off with the routines
  663. which read from a file.
  664.  
  665. If you opened the file for text access, you must want to read
  666. the file a line at a time. Each line is assumed to be less than
  667. 256 characters and delimited by a carriage return and linefeed
  668. (<CR><LF>, or ^M^J, in normal notation). In that case, you
  669. should use the FReadLn$ function:
  670.  
  671.    St$ = FReadLn$(Handle%)
  672.  
  673.                         File Handling                  page 16
  674.  
  675.  
  676.  
  677. A simple program to display a text file directly on the screen
  678. might look something like this in BASIC:
  679.  
  680.    OPEN COMMAND$ FOR INPUT AS #1
  681.    WHILE NOT EOF(1)
  682.       LINE INPUT#1, St$
  683.       PRINT St$
  684.    WEND
  685.    CLOSE #1
  686.  
  687. The same program using BasWiz would look something like this:
  688.  
  689.    REM $INCLUDE: 'BASWIZ.BI'
  690.    FInit 5, ErrCode%
  691.    FOpen COMMAND$, "RT", 0, Handle%, ErrCode%
  692.    WHILE NOT FEOF%(Handle%)
  693.       PRINT FReadLn$(Handle%)
  694.    WEND
  695.    FDone
  696.  
  697. In either case, we're accepting a command-line parameter which
  698. specifies the name of the file. In the BasWiz example, note the
  699. use of the FEOF% function, which tells whether we've gone past
  700. the end of the file. This works like the EOF function in BASIC.
  701.  
  702. There are two ways of reading from binary files. You can get the
  703. results as a string of a specified (maximum) length:
  704.  
  705.    St$ = FRead$(Handle%, Bytes%)
  706.  
  707. In plain BASIC, the same thing might be expressed this way:
  708.  
  709.    St$ = INPUT$(Bytes%, FileNumber%)
  710.  
  711. The other way of reading from a binary file has no equivalent in
  712. BASIC. It allows you to read in up to 32K bytes at a time,
  713. directly into an array or TYPEd variable. You can read the
  714. information into anything that doesn't contain normal strings
  715. (the fixed-length string type can be used, though):
  716.  
  717.    Segm% = VARSEG(Array(0))
  718.    Offs% = VARPTR(Array(0))
  719.    FBlockRead Handle%, Segm%, Offs%, Bytes%
  720.  
  721. That would read the specified number of bytes into Array(),
  722. starting at array element zero.
  723.  
  724.                         File Handling                  page 17
  725.  
  726.  
  727.  
  728. You can use any data type, whether single variable or array, as
  729. long as it is not a variable length string. In other words, Vbl$
  730. and Vbl$(0) would not work. If you want to use a string with the
  731. block read, it must be a fixed-length string. For example:
  732.  
  733.    DIM Vbl AS STRING * 1024
  734.    Segm% = VARSEG(Vbl)
  735.    Offs% = VARPTR(Vbl)
  736.    FBlockRead Handle%, Segm%, Offs%, Bytes%
  737.  
  738. It's a good idea to calculate the Segment and Offset values each
  739. time. These tell FBlockRead where to store the information it
  740. reads. BASIC may move the variables around in memory, so VARSEG
  741. and VARPTR should be used just before FBlockRead to ensure that
  742. they return current information.
  743.  
  744. The file output commands are similar. File output can only be
  745. done if there is no input buffer. This means that you can't use
  746. file output if the file was opened in text mode, either, since
  747. text mode always requires an input buffer. That's a limitation
  748. that will be removed in a future version of BasWiz. It is
  749. possible to do text output on a file that was opened in binary
  750. mode, however. The limitation just means that you can't open a
  751. file for both reading and writing if you use a buffer (or text
  752. mode).
  753.  
  754. To output (write) a string to a file, use this:
  755.  
  756.    FWrite Handle%, St$
  757.  
  758. This is like the plain BASIC statement:
  759.  
  760.    PRINT #FileNumber%, St$;
  761.  
  762. If you would like the string to be terminated by a carriage
  763. return and linefeed, use this instead:
  764.  
  765.    FWriteLn Handle%, St$
  766.  
  767. This is like the plain BASIC statement:
  768.  
  769.    PRINT #FileNumber%, St$
  770.  
  771. In BASIC, the difference between the two writes is controlled by
  772. whether you put a semicolon at the end. With BasWiz, different
  773. routines are used instead. FWrite is like PRINT with a semicolon
  774. and FWriteLn is like PRINT without a semicolon.
  775.  
  776.                         File Handling                  page 18
  777.  
  778.  
  779.  
  780. As well as simple string output, you can also output TYPEd
  781. variables and even entire arrays. This type of output has no
  782. corresponding BASIC instruction, although it's somewhat similar
  783. to the file PUT statement. Up to 32K can be output at a time:
  784.  
  785.    Segm% = VARSEG(Array(0))
  786.    Offs% = VARPTR(Array(0))
  787.    FBlockWrite Handle%, Segm%, Offs%, Bytes%
  788.  
  789. If you haven't already read the section on FBlockRead, go back a
  790. page and review it. The same comments apply for FBlockRead: it
  791. can handle fixed-length strings but not old-style strings, and
  792. VARSEG/VARPTR should immediately precede the block I/O, among
  793. other things.
  794.  
  795. Normally, reads and writes take place sequentially. If you want
  796. to move to a specific spot in the file, though, that's easy. You
  797. can do it in text mode or binary mode, whether or not you have a
  798. buffer, giving you additional flexibility over the usual BASIC
  799. file handling. Set the location for the next read or write, so:
  800.  
  801.    FLocate Handle%, Position&
  802.  
  803. The Position& specified will be where the next read or write
  804. takes place. It starts at one and (since it's specified as a
  805. LONG integer) can go up to however many bytes are in the file.
  806. If you want a record position rather than a byte position, you
  807. can do that too. Just convert the record number to a byte
  808. number, like so:
  809.  
  810.    Position& = (RecordNumber& - 1&) * RecordLength& + 1&
  811.  
  812. If you do not want to maintain RecordNumber and RecordLength as
  813. LONG integers, convert them to such by using the CLNG() function
  814. on them before doing the calculation. Otherwise you may get an
  815. overflow error in the calculation, since QuickBasic will assume
  816. that the result will be an integer.
  817.  
  818. You can get the current position of the file read/write pointer
  819. too:
  820.  
  821.    Position& = FGetLocate&(Handle%)
  822.  
  823. Let's see... we've examined initialization and termination,
  824. opening and closing, reading and writing, and manipulating the
  825. file read/write pointer. What else could there be? Well, how
  826. about checking the size of a file and getting or setting the
  827. file time and date? Why, sure! The "get" routines are pretty
  828. well self-explanatory:
  829.  
  830.    FileSize& = FGetSize&(Handle%)
  831.    FileTime$ = FGetTime$(Handle%)
  832.    FileDate$ = FGetDate$(Handle%)
  833.  
  834.                         File Handling                  page 19
  835.  
  836.  
  837.  
  838. Setting the time and date is equally easy. This should be done
  839. just before you close the file with FClose or FDone. You may use
  840. any date and time delimiters you choose. If a field is left
  841. blank, the appropriate value from the current time or date will
  842. be used. Years may be specified in four-digit or two-digit
  843. format. Two-digit years will be assumed to be in the 20th
  844. century ("90" == "1990"). Careful there! Your program should
  845. allow four-digit dates to be used or disaster will strike when
  846. the year 2000 rolls around. The 21st century is closer than you
  847. think!
  848.  
  849.    FTime Handle%, FileTime$
  850.    FDate Handle%, FileDate$
  851.  
  852. There's just one more file routine. It allows you to "flush" a
  853. file to disk. This insures that the file has been properly
  854. updated to the current point, so nothing will be lost if there
  855. is a power outage or similar problem. If you do not use the
  856. "flush" routine, data may be lost if the program terminates
  857. unexpectedly. Note that use of FFlush requires that a free file
  858. handle be available, before DOS 4.0.
  859.  
  860.    FFlush Handle%
  861.  
  862. That's it for the BasWiz file handler. As a quick review, let's
  863. run through the available routines, then try a couple of example
  864. programs. You might also wish to examine the WDEMO.BAS program,
  865. which also makes use of the file routines.
  866.  
  867. FInit         initialize the file handler
  868. FDone         end the file handler and close any open files
  869.  
  870. FOpen         open a file for access (like OPEN)
  871. FClose        close a file (like CLOSE)
  872.  
  873. FRead$        read a string from a binary file (like INPUT$)
  874. FReadLn$      read a string from a text file (like LINE INPUT)
  875. FBlockRead    read an item from a binary file
  876.  
  877. FWrite        write a string to a binary file
  878. FWriteLn      write a string with a <CR><LF> to a binary file
  879. FBlockWrite   write an item to a binary file
  880.  
  881. FLocate       set the read/write pointer to a given position
  882. FTime         set the time stamp
  883. FDate         set the date stamp
  884. FError        set the error code
  885.  
  886. FGetLocate&   get the read/write pointer
  887. FGetTime$     get the time stamp
  888. FGetDate$     get the date stamp
  889. FGetError     get the error code
  890.  
  891. FFlush        flush to disk (makes sure file is updated)
  892. FGetSize&     get size
  893. FEOF          see if the end of the file has been reached
  894.  
  895.                         File Handling                  page 20
  896.  
  897.  
  898.  
  899. So much for theory. Let's try something practical. A common
  900. problem is copying one file to another. We'll limit this to text
  901. files, so we can do it in both plain BASIC and with BasWiz.
  902. Although BasWiz can handle any type of file readily, BASIC has
  903. problems in efficiently handling variable-length binary files.
  904. So, we'll do this first in BASIC, then BasWiz, for text files.
  905.  
  906. In BASIC, a text-file copying program might look like this:
  907.  
  908.    INPUT "File to copy"; FromFile$
  909.    INPUT "Copy file to"; ToFile$
  910.    OPEN FromFile$ FOR INPUT AS #1
  911.    OPEN ToFile$ FOR OUTPUT AS #2
  912.    WHILE NOT EOF(1)
  913.       LINE INPUT#1, St$
  914.       PRINT#2, St$
  915.    WEND
  916.    CLOSE
  917.  
  918. With BasWiz, the same program would look more like this:
  919.  
  920.    REM $INCLUDE: 'BASWIZ.BI'
  921.    INPUT "File to copy"; FromFile$
  922.    INPUT "Copy file to"; ToFile$
  923.    FInit 15, ErrCode%
  924.    FOpen FromFile$, "RT", 1024, FromHandle%, ErrCode%
  925.    FOpen ToFile$, "CW", 0, ToHandle%, ErrCode%
  926.    FileTime$ = FGetTime$(FromHandle%)
  927.    FileDate$ = FGetDate$(FromHandle%)
  928.    WHILE NOT FEOF%(FromHandle%)
  929.       WriteLn ToHandle%, ReadLn$(FromHandle%)
  930.    WEND
  931.    FTime ToHandle%, FileTime$
  932.    FDate ToHandle%, FileDate$
  933.    FDone
  934.  
  935. You might have noticed that the BasWiz version of the program is
  936. a bit longer than the plain BASIC version. It has a number of
  937. advantages, however. It's faster, produces smaller code under
  938. ordinary circumstances, and preserves the date and time of the
  939. original file in the copied file. Unlike some of the BASIC
  940. compilers, the BasWiz routines do not automatically add a ^Z to
  941. the end of text files, so the BasWiz example will not alter the
  942. original file.
  943.  
  944.                            Fractions                   page 21
  945.  
  946.  
  947.  
  948. Using BCD allows you to represent numbers with excellent
  949. precision, but at a fairly large cost in speed. Another way to
  950. represent numbers with good precision is to use fractions.
  951. Fractions can represent numbers far more accurately than BCD,
  952. but can be handled much more quickly. There are limitations, of
  953. course, but by now you've guessed that's always true!
  954.  
  955. Each fraction is represented by BasWiz as an 8-byte string. The
  956. numerator (top part of the fraction) may be anywhere from
  957. -999,999,999 to 999,999,999. The denominator (the bottom part)
  958. may be from 1 to 999,999,999. This allows handling a fairly wide
  959. range of numbers exactly.
  960.  
  961. Fractions can be converted to or from numeric text strings in
  962. any of three formats: real number (e.g., "1.5"), plain fraction
  963. (e.g., "3/2"), or whole number and fraction (e.g., "1 1/2").
  964. Internally, the numbers are stored as a plain fraction, reduced
  965. to the smallest fraction possible which means the same thing
  966. (for instance, "5/10" will be reduced to "1/2").
  967.  
  968. To convert a numeric text string into a fraction, do this:
  969.  
  970.    Nr$ = FracSet$(NumSt$)
  971.  
  972. To convert a fraction into a numeric text string, try this:
  973.  
  974.    NumSt$ = FracFormat$(Nr$, HowToFormat%)
  975.  
  976. The formatting options are:
  977.  
  978.    0   convert to plain fraction
  979.    1   convert to whole number and fraction
  980.    2   convert to decimal number
  981.  
  982. Here is a list of the other functions available:
  983.  
  984.    Result$ = FracAbs$(Nr$)            ' absolute value
  985.    Result$ = FracAdd$(Nr1$, Nr2$)     ' Nr1 + Nr2
  986.    Result% = FracCompare%(Nr1$, Nr2$) ' compare two fractions
  987.    Result$ = FracDiv$(Nr1$, Nr2$)     ' Nr1 / Nr2
  988.    Result$ = FracMul$(Nr1$, Nr2$)     ' Nr1 * Nr2
  989.    Result$ = FracNeg$(Nr$)            ' - Nr
  990.    Result% = FracSgn%(Nr$)            ' signum function
  991.    Result$ = FracSub$(Nr1$, Nr2$)     ' Nr1 - Nr2
  992.  
  993. Fractions are automatically reduced to allow the greatest
  994. possible range. Note that little range-checking is done at this
  995. point, so you may wish to screen any input to keep it
  996. reasonable.
  997.  
  998.    Result     FracSgn      FracCompare
  999.      -1       negative #    1st < 2nd
  1000.       0       # is zero     1st = 2nd
  1001.       1       positive #    1st > 2nd
  1002.  
  1003.                  Graphics: General Routines            page 22
  1004.  
  1005.  
  1006.  
  1007. These routines are designed to work with specific graphics
  1008. modes, so your program will only include those routines which
  1009. apply to the modes you use. These modes are supported:
  1010.  
  1011.  SCREEN   Card     Graph. Res   Colors   Text Res.       Notes
  1012.  ======   ====     ==========   ======   =============   =====
  1013.     0      any       varies       16     varies            *0
  1014.     1      CGA     320 x 200       4     40 x 25
  1015.     2      CGA     640 x 200       2     80 x 25
  1016.     3      HGA     720 x 348       2     90 x 43           *1
  1017.     7      EGA     320 x 200      16     40 x 25
  1018.     8      EGA     640 x 200      16     80 x 25
  1019.     9      EGA     640 x 350      16     80 x 25/43
  1020.    10      EGA     640 x 350       4     80 x 25/43       mono
  1021.    11      VGA     640 x 480       2     80 x 30/60
  1022.    12      VGA     640 x 480      16     80 x 30/60
  1023.    13      VGA     320 x 200     256     40 x 25
  1024.  --------------------------------------------------------------
  1025.    GV     VESA      <varies>   <varies>  <varies>          *7
  1026.    N0      VGA     360 x 480     256     45 x 30           *2
  1027.    N1      VGA     320 x 400     256     40 x 25           *2
  1028.    N2   <printer>  480 x 640       2     60 x 80/45/40     *3
  1029.    N4      any      80 x  50       2      6 x 10           *4
  1030.    N5     SVGA    <user spec>    256     <varies>          *5
  1031.    N6      MDA      80 x 25      ---     25 x 80           *6
  1032.  
  1033. The number of rows of text available depends on the font size:
  1034. 8 x 8, 8 x 14, or 8 x 16.
  1035.  
  1036. *0  This is actually for text mode, not graphics mode.
  1037.  
  1038. *1  The BasWiz Hercules routines don't need Microsoft's QBHERC
  1039.     TSR to be loaded. This may confuse the BASIC editor. In that
  1040.     case, use BC.EXE to compile the program directly.
  1041.  
  1042. *2  This non-standard VGA mode works on most ordinary VGAs.
  1043.  
  1044. *3  This works with Epson-compatible dot matrix printers and
  1045.     HP-compatible laser printers. The results may be previewed
  1046.     on a VGA. See "Printer Routines".
  1047.  
  1048. *4  This actually provides graphics in text mode for any display
  1049.     adapter. 80x25 text remains available via PRINT.
  1050.  
  1051. *5  This mode provides support for high-resolution 256-color
  1052.     on SuperVGAs based on the popular Tseng ET4000 chips.
  1053.  
  1054. *6  This mode provides support for the monochrome monitor of a
  1055.     dual-monitor system. It works when the mono display is the
  1056.     (theoretically) "inactive" display.
  1057.  
  1058. *7  This mode provides support for the VESA graphics standard,
  1059.     which is common on SuperVGAs. See "VESA Info Routines".
  1060.  
  1061.                  Graphics: General Routines            page 23
  1062.  
  1063.  
  1064.  
  1065. Compatibility: An EGA can display CGA modes. A VGA can display
  1066. EGA and CGA modes. An MCGA can display CGA modes and two VGA
  1067. modes: SCREEN 11 and SCREEN 13. See "Miscellaneous Notes" for
  1068. additional information.
  1069.  
  1070. The routine for a specific mode is indicated by a prefix of "G",
  1071. followed by the mode number, and then the routine name. For
  1072. example, if you wished to plot a point in SCREEN 2 mode, you
  1073. would use:
  1074.  
  1075.    G2Plot X%, Y%
  1076.  
  1077. Many of these routines correspond with existing BASIC
  1078. instructions. However, they are smaller and usually faster by
  1079. 22% - 64%. See "Miscellaneous Notes" for notes on the
  1080. differences between BASIC and the BasWiz routines.
  1081.  
  1082. The smaller size may not be noticeable if you use the SCREEN
  1083. statement, since that causes BASIC to link in some of its own
  1084. graphics routines. If you intend to use only BasWiz routines for
  1085. graphics, you can avoid that by using the G#Mode command instead
  1086. of SCREEN:
  1087.  
  1088.    G#Mode Graphics%         ' 0 for SCREEN 0, else SCREEN #
  1089.  
  1090. If you're using the mode N5 routines, you'll need to initialize
  1091. them before setting the mode. This is done by specifying the
  1092. BIOS mode number and the screen resolution:
  1093.  
  1094.    GN5Init BIOSMode%, PixelsWide%, PixelsHigh%
  1095.  
  1096. The mode GV routines need to be initialized before you set the
  1097. mode and shut down before your program terminates. Also, you
  1098. specify the actual VESA mode number when setting the mode.
  1099.  
  1100.    GGVInit              ' before setting the mode
  1101.    GGVMode VESAmode%    ' to set a VESA mode
  1102.    GGVDone              ' when done using VESA modes
  1103.  
  1104. One difference between BASIC and BasWiz is that, instead of each
  1105. "draw" command requiring a color parameter as in BASIC, the
  1106. BasWiz library provides a separate color command:
  1107.  
  1108.    G#Color Foreground%, Background%
  1109.  
  1110. The "foreground" color is used by all graphics routines. The
  1111. background color is used by the G#Cls routine. Both foreground
  1112. and background colors are used in the G#Write and G#WriteLn
  1113. routines.
  1114.  
  1115.                  Graphics: General Routines            page 24
  1116.  
  1117.  
  1118.  
  1119. Here is a list of the corresponding routines, first BASIC, then
  1120. BasWiz (replace the "#" with the appropriate mode number):
  1121.  
  1122.    ' get the color of a specified point
  1123.    colour% = POINT(x%, y%)
  1124.    colour% = G#GetPel(x%, y%)
  1125.  
  1126.    ' set the color of a specified point
  1127.    PSET (x%, y%), colour%
  1128.    G#Color colour%, backgnd% : G#Plot x%, y%
  1129.  
  1130.    ' draw a line of a specified color
  1131.    LINE (x1%, y1%) - (x2%, y2%), colour%
  1132.    G#Color colour%, backgnd% : G#Line x1%, y1%, x2%, y2%
  1133.  
  1134.    ' draw a box frame of a specified color
  1135.    LINE (x1%, y1%) - (x2%, y2%), colour%, B
  1136.    G#Color colour%, backgnd% : G#Box x1%, y1%, x2%, y2%, 0
  1137.  
  1138.    ' draw a box of a specified color and fill it in
  1139.    LINE (x1%, y1%) - (x2%, y2%), colour%, BF
  1140.    G#Color colour%, backgnd% : G#Box x1%, y1%, x2%, y2%, 1
  1141.  
  1142.    ' clear the screen and home the cursor
  1143.    CLS
  1144.    G#Cls
  1145.  
  1146.    ' get the current cursor position
  1147.    Row% = CSRLIN: Column% = POS(0)
  1148.    G#GetLocate Row%, Column%
  1149.  
  1150.    ' set the current cursor position
  1151.    LOCATE Row%, Column%
  1152.    G#Locate Row%, Column%
  1153.  
  1154.    ' display a string without a carriage return and linefeed
  1155.    PRINT St$;
  1156.    G#Write St$
  1157.  
  1158.    ' display a string with a carriage return and linefeed
  1159.    PRINT St$
  1160.    G#WriteLn St$
  1161.  
  1162. Note that BasWiz, unlike BASIC, allows both foreground and
  1163. background colors for text in graphics mode. It also displays
  1164. text substantially faster than BASIC. See the "Miscellaneous
  1165. Notes" section for information on other differences in text
  1166. printing.
  1167.  
  1168.                  Graphics: General Routines            page 25
  1169.  
  1170.  
  1171.  
  1172. If you need to print a number rather than a string, just use the
  1173. BASIC function STR$ to convert it. If you don't want a leading
  1174. space, use this approach:
  1175.  
  1176.    St$ = LTRIM$(STR$(Number))
  1177.  
  1178. The BasWiz library has other routines which have no BASIC
  1179. equivalent. One allows you to get the current colors:
  1180.  
  1181.    G#GetColor Foreground%, Background%
  1182.  
  1183. Sometimes the normal text services seem unduly limited. Text is
  1184. displayed only at specific character positions, so it may not
  1185. align properly with a graph, for instance. Text is also of only
  1186. one specific size. These are limitations which make the normal
  1187. text routines very fast, but for times when you need something a
  1188. little bit more fancy, try:
  1189.  
  1190.    G#Banner St$, X%, Y%, Xmul%, Ymul%
  1191.  
  1192. You may display the string starting at any graphics position.
  1193. The Xmul% and Ymul% values are multipliers, specifying how many
  1194. times larger than normal each character should be. Use Xmul% = 1
  1195. and Ymul% = 1 for normal-sized characters. What "normal" means
  1196. depends on size of the font in use.
  1197.  
  1198. Since G#Banner "draws" the text onto the screen, it is a bit
  1199. slower than the normal text services. It also uses only the
  1200. foreground color, so the letters go right on top of anything
  1201. that was previously there. Use G#Box to clear the area
  1202. beforehand if this is a problem for you.
  1203.  
  1204. The G#Banner routine supports several fonts. The larger fonts
  1205. provide a more precise character set but leave you with less
  1206. room on the screen. You may choose from these fonts:
  1207.  
  1208.    Font Number     Font Size (width x height)
  1209.         0            8 x 8    --- default
  1210.         1            8 x 14
  1211.         2            8 x 16
  1212.  
  1213. Select a font like so:
  1214.  
  1215.    BFont FontNr%
  1216.  
  1217. If you want to find out what the current font is, can do:
  1218.  
  1219.    FontNr% = GetBFont
  1220.  
  1221. Besides looking more elegant, the larger fonts are easier to
  1222. read. They will also suffer less from being increased in size,
  1223. although some deterioration is inevitable when magnifying these
  1224. kinds of fonts.
  1225.  
  1226.                  Graphics: General Routines            page 26
  1227.  
  1228.  
  1229.  
  1230. The G#Banner routines accept CHR$(0) - CHR$(127). No control
  1231. code interpretation is done. All codes are displayed directly to
  1232. the screen.
  1233.  
  1234. Circles and ellipses can be drawn with the Ellipse routine. This
  1235. is similar to the BASIC CIRCLE statement. You specify the center
  1236. of the ellipse (X,Y), plus the X and Y radius values:
  1237.  
  1238.    G#Ellipse CenterX%, CenterY%, XRadius%, YRadius%
  1239.  
  1240. A circle is an ellipse with a constant radius. So, to draw a
  1241. circle, just set both radius values to the same value.
  1242.  
  1243. As well as the usual points, lines, and ellipses, BasWiz also
  1244. allows you to draw polygons: triangles, squares, pentagons,
  1245. hexagons, all the way up to full circles!
  1246.  
  1247.    G#Polygon X%, Y%, Radius%, Vertices%, Angle!
  1248.  
  1249. The X% and Y% values represent the coordinates of the center of
  1250. the polygon. The Radius% is the radius of the polygon (as if you
  1251. were fitting it into a circle). Vertices% is the number of
  1252. angles (also the number of sides) for the polygon to have.
  1253. Angle! specifies the rotation of the polygon, and is specified
  1254. in radians. See "A Little Geometry" for more information.
  1255.  
  1256. Another routine is designed to manipulate a GET/PUT image. Given
  1257. an image in array Original%() and a blank array of the same
  1258. dimensions called Flipped%(), this routine copies the original
  1259. image to the new array as a mirror image about the horizontal
  1260. axis. This is the same as the image you'd see if you turned your
  1261. monitor upside-down: the resulting image is upside-down and
  1262. backwards.
  1263.  
  1264.    G#MirrorH Original%(), Flipped%()
  1265.  
  1266. Don't forget to make the Flipped%() array the same DIM size as
  1267. the original, or the picture will overflow into main memory,
  1268. probably causing disaster!
  1269.  
  1270. Note that G#MirrorH will only work properly on images with byte
  1271. alignment. This means that the width of the image must be evenly
  1272. divisible by four if SCREEN 1 is used, or evenly divisible by
  1273. eight if SCREEN 2 is used. EGA modes are not yet supported for
  1274. this routine.
  1275.  
  1276. There are more routines that work only with SCREEN 2. One allows
  1277. you to load a MacPaint-type image ("ReadMac" or .MAC files) into
  1278. an array which can then be PUT onto the screen:
  1279.  
  1280.    G2LoadMAC FileName$, Image%(), StartRow%
  1281.  
  1282.                  Graphics: General Routines            page 27
  1283.  
  1284.  
  1285.  
  1286. Note that a full .MAC picture is 576x720, which won't fit on the
  1287. screen, so the image will be truncated to 576x200. You may
  1288. specify a starting row within the .MAC image, StartRow%, which
  1289. may be 0-521, allowing the entire picture to be loaded in
  1290. several parts.
  1291.  
  1292. The Image%() must be dimensioned with 7202 elements:
  1293.  
  1294.    DIM Array(1 TO 7202) AS INTEGER
  1295.  
  1296. If you don't give an extension in the FileName$, an extension of
  1297. ".MAC" will be used. There is no checking to see if the file
  1298. actually exists, so you may wish to do this beforehand.
  1299.  
  1300. There is no way of knowing whether a .MAC picture is supposed to
  1301. be black on white or white on black. If the image doesn't look
  1302. right when you PUT using PSET, you can switch it around by using
  1303. PUT with PRESET instead.
  1304.  
  1305. PC PaintBrush (.PCX) pictures can also be loaded. These images
  1306. can be of various sizes, so you need to dimension a dynamic
  1307. array for them:
  1308.  
  1309.    REM $DYNAMIC
  1310.    DIM Image(1 TO 2) AS INTEGER
  1311.  
  1312. The array will be set to the correct size by the loader. It goes
  1313. like this:
  1314.  
  1315.    G2LoadPCX FileName$, Image%(), ErrCode%
  1316.  
  1317. If you don't give an extension in the FileName$, an extension of
  1318. ".PCX" will be used. You may wish to check to see if the file
  1319. exists beforehand. Possible errors are as follows:
  1320.  
  1321.    -1   File is not in PCX format
  1322.     1   Image is too large for this screen mode
  1323.     2   Image won't work in this screen mode (too many planes)
  1324.  
  1325. Two new routines are replacements for the GET and PUT image
  1326. statements in BASIC. They are on the slow side, but if you don't
  1327. intend to use them for animation, they will serve to save some
  1328. memory. There are also GN5Get and GN5Put routines for use with
  1329. 256-color SuperVGA modes.
  1330.  
  1331.    REM $DYNAMIC
  1332.    DIM Image(1 TO 2) AS INTEGER
  1333.    G2Get X1%, Y1%, X2%, Y2%, Image()
  1334.  
  1335. Note the DIMensioning of a dynamic array. The G2Get routine will
  1336. set the array to the appropriate size to hold the image.
  1337.  
  1338.                  Graphics: General Routines            page 28
  1339.  
  1340.  
  1341.  
  1342. The PUT replacement assumes that you intend to PSET the image.
  1343. It doesn't allow for other display modes yet:
  1344.  
  1345.    G2Put X%, Y%, Image()
  1346.  
  1347. See "Miscellaneous Notes" for more information on using GET/PUT
  1348. images and the directions I'll be taking with them in the
  1349. future. Note that SCREEN 13 is also supported, via G13Get and
  1350. G13Put.
  1351.  
  1352. Windows 256-color bitmaps may displayed in, or written from, any
  1353. of the VGA or SVGA modes which support 256 colors. This includes
  1354. modes 13, GV, N0, N1, and N5. Since BasWiz file handling is
  1355. employed, you must be sure to initialize the file handler with
  1356. FInit before using these routines and close the file handler
  1357. with FDone before your program terminates. The graphics mode
  1358. must be set beforehand. When reading a BMP, the palette will be
  1359. initialized according to the settings in the .BMP file.
  1360.  
  1361.    G#ShowBMP FileName$, X%, Y%, ErrCode%
  1362.  
  1363.    G#MakeBMP FileName$, X1%, Y1%, X2%, Y2%, ErrCode%
  1364.  
  1365. A bitmap can only be displayed if the screen resolution is
  1366. sufficient to hold the entire image. You can read the .BMP
  1367. information using the following routine:
  1368.  
  1369.    GetInfoBMP FileName$, Wide%, High%, Colors%, ErrCode%
  1370.  
  1371. A positive error code indicates a DOS error code, which is a
  1372. problem in reading the file. Negative error codes are one of the
  1373. following:
  1374.  
  1375.    -1   not a valid .BMP file
  1376.    -2   color format not supported
  1377.    -3   compression type not supported
  1378.    -4   incorrect file size
  1379.    -5   unreasonable image size
  1380.    -6   invalid (X,Y) origin specified for G#ShowBMP
  1381.  
  1382.                  Graphics: General Routines            page 29
  1383.  
  1384.  
  1385.  
  1386. The COLOR statement in SCREEN 1 is anomalous. It doesn't really
  1387. control color at all, which is why QuickBasic proper doesn't
  1388. support colored text in this (or any graphics) mode. Instead, it
  1389. is used for controlling the background/border color and palette.
  1390. Since BasWiz -does- support a true G1COLOR routine, there are
  1391. different routines which allow you to change the palette and
  1392. border colors. To change the background (and border) color, use:
  1393.  
  1394.    G1Border Colour%
  1395.  
  1396. There are two palette routines. Why two? Well, QuickBasic
  1397. supports two CGA palettes. One of the routines works like
  1398. QuickBasic and can be used on any CGA, EGA or VGA display (as
  1399. long as it's in CGA mode). The other routine gives you a wider
  1400. choice of palettes, but will only work on true CGAs (and some
  1401. EGA or VGA systems that have been "locked" into CGA mode).
  1402.  
  1403. Here's the QuickBasic-style two-palette routine for any
  1404. CGA/EGA/VGA:
  1405.  
  1406.    G1PaletteA PaletteNr%
  1407.  
  1408. The PaletteNr% may be as follows:
  1409.  
  1410.    0     (bright) Green, Red, Yellow
  1411.    1     Cyan, Violet, White
  1412.  
  1413.  
  1414. The more flexible six-palette routine (for CGA only) works like
  1415. this:
  1416.  
  1417.    G1PaletteB PaletteNr%
  1418.  
  1419. Palettes are as follows:
  1420.  
  1421.    0  Green, Red, Brown        4  (bright) Green, Red, Yellow
  1422.    1  Cyan, Violet, White      5  (bright) Cyan, Violet, White
  1423.    2  Cyan, Red, White         6  (bright) Cyan, Red, White
  1424.  
  1425.                  Graphics: General Routines            page 30
  1426.  
  1427.  
  1428.  
  1429. The EGA has a number of features which work in all its modes, so
  1430. rather than giving them screen mode prefixes, they are simply
  1431. named with an "E". These routines allow you to get or set the
  1432. palette, get or set the border color, and determine whether the
  1433. higher background colors should be displayed as bright colors or
  1434. as blinking.
  1435.  
  1436. To get a palette color value, use:
  1437.  
  1438.    Colour% = EGetPalette(ColorNumber%)
  1439.  
  1440. To set the color value, use:
  1441.  
  1442.    EPalette ColorNumber%, Colour%
  1443.  
  1444. To get the border color:
  1445.  
  1446.    Colour% = EGetBorder%
  1447.  
  1448. You can probably guess how to set the border color:
  1449.  
  1450.    EBorder Colour%
  1451.  
  1452. Finally, the blink vs. intensity. Actually, this is designed for
  1453. text mode; I'm not sure whether it has any function in graphics
  1454. modes. The text-mode default is for blinking to be turned on.
  1455. With BASIC, you add 16 to the foreground color to make it blink.
  1456. That's a little weird, since the "blink" attribute is actually a
  1457. part of the background color, but that's how BASIC views it. You
  1458. can tell the EGA to turn off blinking, in which case adding 16
  1459. to the foreground color makes the background color intense. This
  1460. doubles the number of available background colors.
  1461.  
  1462.    EBlink Blink%
  1463.  
  1464. Use -1 for blinking (default), or 0 to turn off blinking.
  1465.  
  1466. Like the EGA, the VGA has a number of features which work in all
  1467. its modes. Again, rather than giving them screen mode prefixes,
  1468. we simply name them with a "V". The current routines allow you
  1469. to get or set the palette colors.
  1470.  
  1471. To get a palette color value, use:
  1472.  
  1473.    VGetPalette ColorNumber%, Red%, Green%, Blue%
  1474.  
  1475. To set the color value, use:
  1476.  
  1477.    VPalette ColorNumber%, Red%, Green%, Blue%
  1478.  
  1479.                  Graphics: General Routines            page 31
  1480.  
  1481.  
  1482.  
  1483. As you've probably noticed, this doesn't work the same way as
  1484. the QuickBasic PALETTE statement. Rather than using a formula to
  1485. calculate a single LONG color value, like QuickBasic, the BasWiz
  1486. library allows you to specify the color in a more meaningful
  1487. way. The Red%, Green%, and Blue% parameters each hold an
  1488. intensity value (0-63). By mixing these three, you can get an
  1489. immense variety of shades-- over 250,000 combinations in all.
  1490.  
  1491. If you need to keep track of the intensities in your program,
  1492. I'd suggest the following TYPE definition:
  1493.  
  1494.    TYPE VGAcolor
  1495.       Red AS INTEGER
  1496.       Green AS INTEGER
  1497.       Blue AS INTEGER
  1498.    END TYPE
  1499.  
  1500. If space is more important than speed, you can compress that to
  1501. half the size by using STRING * 1 instead of INTEGER. In that
  1502. case, you will need to use the CHR$ and ASC functions to convert
  1503. between string and integer values.
  1504.  
  1505.                      VESA Info Routines                page 32
  1506.  
  1507.  
  1508.  
  1509. As IBM's influence decreased in the microcomputer world, there
  1510. came to be a great deal of chaos associated with new graphics
  1511. standards-- or, more precisely, the lack thereof. With each
  1512. manufacturer merrily creating a new SVGA interface, it became
  1513. very difficult to find software which actually supported
  1514. whichever SuperVGA you purchased. The exciting capabilities of
  1515. the new adapters, often as not, turned out to be worthless
  1516. advertising promises. Eventually, the VESA graphics standard was
  1517. created in order to help resolve this problem.
  1518.  
  1519. Most SuperVGAs today offer VESA support, either built into the
  1520. adapter's ROM BIOS, or as an optional TSR or driver. BasWiz
  1521. allows you to see if VESA support is available, and if so, what
  1522. video modes may be used. The best approach to using VESA is to
  1523. offer the user a choice of the modes that VESA reports as
  1524. available, since the monitor may well not support all of the
  1525. modes that the adapter is capable of handling.
  1526.  
  1527. Quite honestly, VESA is not much of a standard. It offers the
  1528. barest minimum needed to access the capabilities of a display,
  1529. and not always even that. The standard allows the manufacturer
  1530. to leave out normal BIOS support for extended video modes,
  1531. though it does recommend that they be supported. BasWiz expects
  1532. a bit more than such sketchy minimalist compliance with VESA.
  1533. Most importantly, BasWiz must be able to access the display
  1534. through the normal BIOS routines, in conjunction with
  1535. appropriate VESA mode handling. If you believe your SVGA
  1536. provides VESA support, but the routines to get mode information
  1537. do not return any valid modes, perhaps your implementation of
  1538. VESA lacks this key feature. Check with the manufacturer. Among
  1539. the things VESA doesn't support, by the way, is modes with more
  1540. than 256 colors-- so BasWiz can't either. Sorry.
  1541.  
  1542. One thing the VESA standard does provide is a great deal of
  1543. information about the available video modes-- their mode
  1544. numbers, graphics and text resolutions, number of colors, and so
  1545. forth. You may access this information through BasWiz whether or
  1546. not you intend to actually use VESA graphics in your program--
  1547. the routines do not need GGVInit to be initialized. Note that
  1548. VESA supports both extended graphics and text modes. The BasWiz
  1549. VESA routines currently support only VESA graphics, which is
  1550. referred to as mode GV. VESA text modes, when implemented, will
  1551. become mode TV. As the VESA information routines do not
  1552. specifically refer to either a text or graphics mode, there is
  1553. no mode number; instead, the routines simply have a prefix of
  1554. VESA.
  1555.  
  1556. The key routine for all of this allows you to see whether VESA
  1557. support is available, and which version of VESA:
  1558.  
  1559.    VesaVersion MajorV%, MinorV%
  1560.  
  1561. The MajorV% value is the major version number, and MinorV% the
  1562. minor version number. If VESA support is not available, both of
  1563. these numbers will be zero.
  1564.  
  1565.                      VESA Info Routines                page 33
  1566.  
  1567.  
  1568.  
  1569. Since VESA is intended to support a wide variety of video modes,
  1570. the mode numbers and specifications are not built into the
  1571. standard as such. Instead, they are part of the VESA driver
  1572. which supports your particular video card. You can ask the
  1573. driver which modes are available and what they are like. BasWiz
  1574. treats this in a way similar to the way DOS lets you seek for
  1575. files: with a "find first" request to initialize the routines
  1576. and search for the first item, followed by any number of "find
  1577. next" requests to find subsequent items.
  1578.  
  1579. The "find first" and "find next" routines return a mode number.
  1580. If the mode number is -1 (negative one), you have reached the
  1581. end of the mode list. Otherwise, it's a video mode number, and
  1582. you can get additional information about the mode with an
  1583. assortment of other functions. This is pretty straightforward,
  1584. so I won't go into detail here. See VESAINFO.BAS for an example
  1585. program which uses all of these functions to tell you about all
  1586. available VESA modes on your display.
  1587.  
  1588.    VMode% = VesaFindFirst%        ' find first mode
  1589.    VMode% = VesaFindNext%         ' find subsequent mode
  1590.  
  1591. These provide results in pixels for graphics modes, or in
  1592. characters for text modes. Note that BasWiz does not yet support
  1593. use of VESA text modes.
  1594.  
  1595.    XSize% = VesaScrWidth%         ' screen width
  1596.    YSize% = VesaScrHeight%        ' screen height
  1597.  
  1598. These describe the size of the character matrix in pixels (use
  1599. for figuring text rows & cols in graphics modes). Note that
  1600. BasWiz requires VesaChrWidth% = 8 for printing, which is the
  1601. usual setting in graphics modes.
  1602.  
  1603.    ChWidth% = VesaChrWidth%       ' character width
  1604.    ChHeight% = VesaChrHeight%     ' character height
  1605.  
  1606. BasWiz supports no more than 256 colors, as neither VESA nor the
  1607. standard BIOS functions were designed for more. If someone can
  1608. send me info on how to handle more colors, I'll see what I can
  1609. do.
  1610.  
  1611.    Colors& = VesaColors&          ' number of colors
  1612.  
  1613. These two return boolean values: -1 if true, 0 if false.
  1614.  
  1615.    Mono% = VesaIsMono%            ' if mode is monochrome
  1616.    Text% = VesaIsText%            ' if it's a text mode
  1617.  
  1618. Scrolling in VESA modes is extremely slow. Avoid if possible.
  1619.  
  1620.                 Graphics: Text-mode Routines           page 34
  1621.  
  1622.  
  1623.  
  1624. It may seem odd to lump text-mode handling in with graphics
  1625. mode. It seemed like the most logical approach, however. There
  1626. is certainly some value in having graphics-type capabilities for
  1627. text mode. The ability to draw lines and boxes, use banner-style
  1628. text, and so forth can be handy. So, for the folks who don't
  1629. need all the power of the virtual windowing system, I've added
  1630. text-mode support into the "graphics" routines.
  1631.  
  1632. There are some quirks to these routines, since text mode doesn't
  1633. work the same way as graphics mode. For one thing, each "pixel"
  1634. is actually an entire character. The default pixel is a solid
  1635. block character, CHR$(219). You can change this, however:
  1636.  
  1637.    G0SetBlock Ch%      ' set ASCII code (use ASC(Ch$))
  1638.    Ch% = G0GetBlock%   ' get ASCII code
  1639.  
  1640. Since a pixel consists of a character with both foreground and
  1641. background colors, the "get pixel" routine has been altered to
  1642. accordingly:
  1643.  
  1644.    G0GetPel X%, Y%, Ch%, Fore%, Back%
  1645.  
  1646. Finally, let's consider the "set mode" command. If you pass it a
  1647. zero, the current mode will be used as-is. This is useful in
  1648. case you've already set up a desired mode.
  1649.  
  1650. Any other mode number will be assumed to be a BIOS video mode
  1651. which should be set. If you feel like initializing the screen
  1652. mode for some reason, it may be useful to know that 3 is the
  1653. normal color mode (for CGA, EGA, VGA, etc) and 7 is the normal
  1654. mono mode (for MDA and Hercules). These provide 80x25 text. If
  1655. you wish to take advantage of 43-row EGA or 50-row VGA text
  1656. modes, you must set them up in advance (using the BASIC
  1657. statements SCREEN and WIDTH) before calling G0Mode with a zero.
  1658.  
  1659. If you have a SuperVGA or other adapter which supports unusual
  1660. text modes, you can use the mode command to switch to the
  1661. appropriate mode. On my Boca SuperVGA, for example, mode &H26
  1662. provides 80x60 text, and mode &H22 provides 132x44. The G0
  1663. routines are designed to support any text resolution up to
  1664. 255x255, provided that the video BIOS properly updates the
  1665. appropriate memory locations when a mode set is done. This
  1666. should be true for any special EGA or VGA-based text modes.
  1667.  
  1668.    G0Mode ModeNr%
  1669.  
  1670.               Graphics: Dual Monitor Routines          page 35
  1671.  
  1672.  
  1673.  
  1674. The N6 mode support dual monitors. To use this mode, you must
  1675. make the color monitor the "active" display, so it can be
  1676. handled with the usual BASIC or BasWiz display routines. The N6
  1677. routines are designed to work with a monochrome monitor only
  1678. when it is the (supposedly) "inactive" display in a dual monitor
  1679. system. The normal BASIC, BIOS, and DOS routines are designed
  1680. with the idea that only one monitor is active at any given time,
  1681. so we let them think what they like, and bypass 'em with a bit
  1682. of fancy footwork.
  1683.  
  1684. These routines are designed for monochrome adapters. Either a
  1685. plain MDA or a Hercules mono graphics adapter will do.
  1686.  
  1687. The notes on SetBlock and GetPel from the explanation of mode 0
  1688. on the previous page apply. In this case, of course, they're
  1689. GN6SetBlock and GN6GetPel, but the functionality is the same.
  1690.  
  1691. In addition, there are two new routines which allow you to get
  1692. and set the cursor size. The cursor size is defined in scan
  1693. lines, which may range from 0 (invisible) to 11 (large block):
  1694.  
  1695.    GN6CursorSize ScanLines%
  1696.    ScanLines% = GN6GetCursorSize%
  1697.  
  1698.                  Graphics: Printer Routines            page 36
  1699.  
  1700.  
  1701.  
  1702. The BasWiz printer routines allow you to work with a printer
  1703. using the same convenient methods you'd use on a screen. The
  1704. image is created with the usual G# routines (using mode N2), but
  1705. the results are kept in a buffer in memory (about 37K bytes)
  1706. rather than being displayed directly. The image can be previewed
  1707. on a VGA or printed out at your convenience, to any printer or
  1708. even a file. The results will take up a single printer page,
  1709. assuming the usual 8.5" x 11" paper is used.
  1710.  
  1711. Printing a finished page works like this:
  1712.  
  1713.    GN2Print Device$     ' for Epson-type dot matrix printers
  1714.    GN2PrintL Device$    ' for HP-type laser printers
  1715.  
  1716. The Device$ variable should be set to the name of the device:
  1717.  
  1718.    LPT1    parallel printer on port 1   (PRN also works)
  1719.    LPT2    parallel printer on port 2
  1720.    LPT3    parallel printer on port 3
  1721.    COM1    serial printer on port 1     (AUX also works)
  1722.    COM2    serial printer on port 2
  1723.  
  1724. Instead of using a device name, you can also use a file name, to
  1725. store the results for later printing. Output is done using BASIC
  1726. file handling, so it would be a good idea to provide an ON ERROR
  1727. GOTO trap in case of problems. The FREEFILE function is used, so
  1728. you don't have to worry about conflicts with any file numbers
  1729. which may be in use by your program.
  1730.  
  1731. Getting a page layout just right can consume a lot of paper.
  1732. Fortunately, there's a "preview" routine that allows you to
  1733. display the results on a VGA. The display will be sideways,
  1734. allowing the whole page to be seen at once. This will exactly
  1735. match the printed output in N2 mode. Here's how it works:
  1736.  
  1737.    G11Mode 1               ' set SCREEN 11 (VGA 640x480 x2)
  1738.    GN2Display              ' display the page
  1739.    DO                      ' wait for a key to be pressed
  1740.    LOOP UNTIL LEN(INKEY$)  '
  1741.    G11Mode 0               ' set SCREEN 0 (text mode)
  1742.  
  1743. The GN2Write and GN2WriteLn printer routines are unlike the
  1744. display versions of the same routines in that they don't scroll.
  1745. These routines only handle one page at a time.
  1746.  
  1747. Before using GN2Write or GN2WriteLn routines, you must choose a
  1748. font with GN2Font. These are the same fonts as used with
  1749. G#Banner:
  1750.  
  1751.     0     8 x 8        80 text rows
  1752.     1     8 x 14       45 text rows
  1753.     2     8 x 16       40 text rows
  1754.  
  1755. The current font can be retrieved with GN2GetFont%. The result
  1756. will be meaningless if the font was never set with GN2Font.
  1757.  
  1758.                  Graphics: A Little Geometry           page 37
  1759.  
  1760.  
  1761.  
  1762. The increasing capabilities of computer graphics systems has
  1763. left many of us in the dust. It's great to be able to run
  1764. dazzling applications or to doodle with a "paint" program, but
  1765. many of us find it difficult to design appealing images of our
  1766. own. Becoming an artist is perhaps a bit more than most of us
  1767. are willing to take on! It is important to remember, however,
  1768. that computers are wonderful number-crunchers. With a little
  1769. application of plane geometry, you can have the computer take on
  1770. much of the work for you-- and after all, isn't that why we have
  1771. computers in the first place?
  1772.  
  1773. A complete review of plane geometry is a bit beyond the scope of
  1774. this text. However, I'm going to run through some of the things
  1775. I think you'll find most useful. I'd also like to suggest that
  1776. you might dig out your old textbooks or rummage through your
  1777. local used book store. It may have seemed like a dry subject at
  1778. the time, but when you can watch the results growing on your
  1779. computer screen, you will have a much better idea of how
  1780. geometry can be useful to you-- and it can be surprisingly fun,
  1781. too!
  1782.  
  1783. In geometry talk, a "point" doesn't have any actual size. In our
  1784. case, we want to apply geometry to physical reality, namely the
  1785. computer screen. As far as we're concerned, a "point" will be an
  1786. individual graphics dot, also called a "pel" or "pixel" (for
  1787. "picture element"). We can safely dispense with such formalities
  1788. for our applications, for the most part.
  1789.  
  1790. The most important thing about a point is that it has a
  1791. location! Ok, that may not seem staggering, but it happens that
  1792. there are a number of ways of specifying that location. The most
  1793. common method is called the Cartesian coordinate system. It is
  1794. based on a pair of numbers: X, which represents the distance
  1795. along a horizontal line, and Y, which represents the distance
  1796. along a vertical line. Consider the CGA in SCREEN 2, for
  1797. instance. It has a coordinate system where X can be 0 - 639 and
  1798. Y can be 0 - 199. The points are mapped on kind of an invisible
  1799. grid.
  1800.  
  1801. The Cartesian coordinate system makes it easy to visualize how a
  1802. given point relates to other points on the same plane (or
  1803. screen). It is particularly useful for drawing lines. Horizontal
  1804. and vertical lines become a cinch: just change the X value to
  1805. draw horizontally, or the Y value to draw vertically. Squares
  1806. and rectangles (or boxes) can be formed by a combination of such
  1807. lines. You can define an area of the screen in terms of an
  1808. imaginary box (as GET and PUT do) with nice, clean boundaries.
  1809. When we get to diagonal lines, it's a bit more of a nuisance,
  1810. but still easy enough with the proper formula. That means we can
  1811. do triangles too. Curves are worse... when it comes to even a
  1812. simple circle or ellipse, the calculations start to get on the
  1813. messy side. For things like that, though, there is an
  1814. alternative.
  1815.  
  1816.                  Graphics: A Little Geometry           page 38
  1817.  
  1818.  
  1819.  
  1820. Another way of describing the location of a point is by Polar
  1821. coordinates. In Cartesian coordinates, the location is specified
  1822. by its horizontal and vertical distances from the "origin" or
  1823. reference point, (0,0). In Polar coordinates, the location is
  1824. specified by its distance and angle from the origin. Think of it
  1825. as following a map: Cartesian coordinates tell you how many
  1826. blocks down and how many blocks over the point is, whereas Polar
  1827. coordinates tell you in which direction the point is and how far
  1828. away it is "as the crow flies".
  1829.  
  1830. The Polar coordinate system is great for describing many kinds
  1831. of curves, much better than Cartesian. For example, a circle is
  1832. defined as all of the points at a given (fixed) distance from a
  1833. center point. Polar coordinates include both a distance and an
  1834. angle, and we've already got the distance, so all we need to do
  1835. is plot points at all of the angles on a circle. Technically,
  1836. there is an infinite number of angles, but since our points
  1837. don't follow the mathematical definition (they have a size), we
  1838. don't have to worry about that.
  1839.  
  1840. Let me digress for a moment to talk about angles. In BASIC,
  1841. angles are specified in "radians". People more often use
  1842. "degrees". Fortunately, it isn't hard to convert from one to the
  1843. other. Both may be visualized on a circle. In radians, the sum
  1844. of the angles in a circle is twice pi. In degrees, the sum of
  1845. the angles is 360. That's something like this:
  1846.  
  1847.  
  1848.                  90 deg, 1/2 * pi rad
  1849.                        /---|---\
  1850.                       /    |    \
  1851.                      /     |     \
  1852.        180 degrees   |___  .  ___|    0 deg, 0 rad; or...
  1853.        pi radians    |           |  360 deg, 2 * pi rad
  1854.                      \     |     /
  1855.                       \    |    /
  1856.                        \---|---/
  1857.                  270 deg, 3/2 * pi rad
  1858.  
  1859.  
  1860. Ok, so that's a grotesquely ugly circle! Hopefully it shows the
  1861. important thing, though. Angles start at zero on the extreme
  1862. right and get larger as they work around counter-clockwise. The
  1863. places marked on the "circle" are places where lines drawn
  1864. horizontally and vertically through the center intersect the
  1865. outside of the circle. These serve as a useful reference point,
  1866. especially in that they help show how the angles can be
  1867. construed from a Cartesian viewpoint.
  1868.  
  1869. So much for angles. I'll go into conversion formulae, the value
  1870. of pi, and other good junk a bit later on. Right now, let's get
  1871. back to our discussion of Polar coordinates.
  1872.  
  1873.                  Graphics: A Little Geometry           page 39
  1874.  
  1875.  
  1876.  
  1877. I've explained how the Polar system makes it easy to draw a
  1878. circle. Since you can vary the range of angles, it's equally
  1879. simple to draw an arc. If you wanted to make a pie chart, you
  1880. might want to join the ends of the arcs to the center of the
  1881. circle, in which case you'd keep the angle constant (at the ends
  1882. of the arc) and plot by changing the distance from zero to the
  1883. radius. Circles are also handy for drawing equilateral
  1884. polygons... you know, shapes with sides of equal length:
  1885. triangle, square, pentagon, hexagon, etc. In this case, the best
  1886. features of the Cartesian and Polar systems can be joined to
  1887. accomplish something that would be difficult in either alone.
  1888.  
  1889. The starting point for these polygons is the circle. Imagine
  1890. that the polygon is inside a circle, with the vertices (pointy
  1891. ends, that is, wherever the sides meet) touching the edge of the
  1892. circle. These are equilateral polygons, so all of the sides and
  1893. angles are the same size. Each of the vertices touches the
  1894. circle, and each does it at exactly the same distance from each
  1895. other along the arc of the circle. All of this detail isn't
  1896. precisely necessary, but I hope it makes the reasoning a bit
  1897. more clear!
  1898.  
  1899. The circle can be considered as being divided by the polygon
  1900. into a number of arcs that corresponds to the number of vertices
  1901. (and sides) the polygon has. Think of a triangle inside a
  1902. circle, with the tips all touching the circle. If you ignore the
  1903. area inside the triangle, you will see that the circle is
  1904. divided into three equal arcs. The same property is true of any
  1905. equilateral polygon. As a matter of fact, as the number of
  1906. vertices goes up, the circle is partitioned into more, but
  1907. smaller, arcs... so that a polygon with a large enough number of
  1908. vertices is effectively a circle itself!
  1909.  
  1910. Anyway, the important thing is the equal partitioning. We know
  1911. how many angles, be they degrees or radians, are in a circle. To
  1912. get the points of a polygon, then... well, we already know the
  1913. "distance" part: that's the same as the radius. The angles can
  1914. be calculated by dividing the angles in the whole circle by the
  1915. number of vertices in the desired polygon. Trying that case with
  1916. the triangle, assuming a radius of 20 (why not), and measuring
  1917. in degrees, that would give us the Polar points (20, 0), (20,
  1918. 120), (20, 240). To make this a triangle, we need to connect the
  1919. points using lines, which is easy in Cartesian coordinates.
  1920. Since the computer likes Cartesian anyway, we just convert the
  1921. Polar coordinates to Cartesian, draw the lines, and viola!
  1922.  
  1923.                  Graphics: A Little Geometry           page 40
  1924.  
  1925.  
  1926.  
  1927. That's essentially the method used by the G#Polygon routines.
  1928. It's very simple in practice, but I haven't seen it elsewhere...
  1929. probably because people forget about the Polar coordinate
  1930. system, which is what makes it all come together. Polar
  1931. coordinates also have simple equations for figures that look
  1932. like daisies, hearts, and other unusual things. See "Equations,
  1933. Etc" and ROSES.BAS for more information.
  1934.  
  1935. On a side note, the Cartesian system isn't used by all
  1936. computers, although it's the most common. Cartesian coordinates
  1937. are the standard for what is called "raster" displays. The Polar
  1938. coordinate system is used on "vector" displays. One example of a
  1939. vector display that you may have seen is the old Asteroids video
  1940. arcade game. Vector displays tend to be used for drawing
  1941. "framework" pictures where the image must be very sharp (unlike
  1942. in raster images, the diagonal lines aren't jagged, since
  1943. there's no raster "grid").
  1944.  
  1945. In this section, I'm going to list a number of equations and so
  1946. forth. Some of them will be useful to you in experimenting with
  1947. Polar coordinates. Some of them provide formulae for things that
  1948. are already in BasWiz, but which you might like to understand
  1949. better. Some of them are just for the heck of it... note that
  1950. not all of this information may be complete enough for you to
  1951. just use without understanding it.
  1952.  
  1953. One problem is... if you try to draw a circle, for instance, it
  1954. will come out looking squashed in most SCREEN modes. Remember we
  1955. said our points, unlike mathematical points, have a size? In
  1956. most graphics modes, the points are effectively wider than they
  1957. are high, so a real circle looks like an ellipse.
  1958.  
  1959. Another problem is that these equations are based on an origin
  1960. of (0,0) which is assumed to be at the center of the plane. In
  1961. our case, (0,0) is at the upper right edge, which also makes the
  1962. Y axis (vertical values) effectively upside-down. This isn't
  1963. necessarily a problem, but sometimes it is! Adding appropriate
  1964. offsets to the plotted X and Y coordinates often fixes it. In
  1965. the case of Y, you may need to subtract the value from the
  1966. maximum Y value to make it appear right-side-up.
  1967.  
  1968. The displayed form of these equations may contain "holes",
  1969. usually again because the points have a size, and/or since we
  1970. try to use integer math to speed things up. If the screen had
  1971. infinite resolution, this would not be a problem... meanwhile
  1972. (!), getting around such problems takes fiddlin'.
  1973.  
  1974.                   Graphics: Equations, Etc             page 41
  1975.  
  1976.  
  1977.  
  1978. There are other problems, mostly due to forcing these
  1979. simplified-universe theoretical equations into practical use.
  1980. It's a lot easier to shoehorn in these simple equations than to
  1981. use more accurate mathematical descriptions, though... a -lot-
  1982. easier. So a few minor quirks can be ignored!
  1983.  
  1984. With those disclaimers, here's the scoop on some handy
  1985. equations.
  1986.  
  1987.    Polar coordinates may be expressed as (R, A), where R is
  1988.    radius or distance from the origin, and A is the angle.
  1989.  
  1990.    Cartesian coordinates may be expressed as (X, Y), where X is
  1991.    the distance along the horizontal axis and Y is the distance
  1992.    along the vertical axis.
  1993.  
  1994.    Polar coordinates can be converted to Cartesian coordinates
  1995.    like so:
  1996.       X = R * COS(A): Y = R * SIN(A)
  1997.  
  1998.    Angles may be expressed in radians or degrees. BASIC prefers
  1999.    radians. Radians are based on PI, with 2 * PI radians in a
  2000.    circle. There are 360 degrees in a circle. Angles increase
  2001.    counter-clockwise from a 3:00 clock position, which is the
  2002.    starting (zero) angle. Angles can wrap around: 720 degrees is
  2003.    the same as 360 degrees or 0 degrees, just as 3:00 am is at
  2004.    the same clock position as 3:00 pm.
  2005.  
  2006.    Angles may be converted between degrees and radians, so:
  2007.       radians = degrees * PI / 180
  2008.       degrees = radians * 180 / PI
  2009.  
  2010.    The value PI is approximately 3.14159265358979. For most
  2011.    graphics purposes, a simple 3.141593 should do quite nicely.
  2012.    The true value of PI is an irrational number (the decimal
  2013.    part repeats forever, as near as anyone can tell). It has
  2014.    been calculated out to millions of decimal points by people
  2015.    with a scientific bent (and/or nothing better to do)!
  2016.  
  2017.                   Graphics: Equations, Etc             page 42
  2018.  
  2019.  
  2020.  
  2021. Line Drawing:
  2022.  
  2023.    One of the convenient ways of expressing the formula of a
  2024.    line (Cartesian coordinates) is:
  2025.       Y = M * X + B
  2026.  
  2027.    Given the starting and ending points for the line, M (the
  2028.    slope, essentially meaning the gradient, of the line) can be
  2029.    determined by:
  2030.       M = (Y2 - Y1) / (X2 - X1)
  2031.  
  2032.    The B value is called the Y-intercept, and indicates where
  2033.    the line intersects with the Y-axis. Given the ingredients
  2034.    above, you can calculate that as:
  2035.       B = Y1 - M * X1
  2036.  
  2037.    With this much figured out, you can use the original formula
  2038.    to calculate the appropriate Y values, given a FOR X = X1 TO
  2039.    X2 sort of arrangement. If the slope is steep, however, this
  2040.    will result in holes in the line. In that case, it will be
  2041.    smoother to recalculate the formula in terms of the X value
  2042.    and run along FOR Y = Y1 TO Y2... in that case, restate it
  2043.    as:
  2044.       X = (Y - B) / M
  2045.  
  2046.    Keep an eye on conditions where X1 = X2 or Y1 = Y2! In those
  2047.    cases, you've got a vertical or horizontal line. Implement
  2048.    those cases by simple loops to improve speed and to avoid
  2049.    dividing by zero.
  2050.  
  2051.  
  2052.  
  2053. Circle Drawing:
  2054.  
  2055.    The Cartesian formula gets messy, especially due to certain
  2056.    aspects of the display that are not accounted for (mainly
  2057.    that pixels, unlike theoretical points, have a size and shape
  2058.    which is usually rectangular). The Polar formula is trivial,
  2059.    though. The radius should be specified to the circle routine,
  2060.    along with the center point. Do a FOR ANGLE! = 0 TO 2 * PI!
  2061.    STEP 0.5, converting the resulting (Radius, Angle)
  2062.    coordinates to Cartesian, then adding the center (X,Y) as an
  2063.    offset to the result. The appropriate STEP value for the loop
  2064.    may be determined by trial and error. Smaller values make
  2065.    better circles but take more time. Larger values may leave
  2066.    "holes" in the circle.
  2067.  
  2068.                   Graphics: Equations, Etc             page 43
  2069.  
  2070.  
  2071.  
  2072. Spiral Drawing:
  2073.  
  2074.    If you use Polar coordinates, this is easy. Just treat it
  2075.    like a circle, but decrease the radius as you go along to
  2076.    spiral in... or increase the radius as you go along if you
  2077.    prefer to spiral out.
  2078.  
  2079.  
  2080.  
  2081. Polygon Drawing:
  2082.  
  2083.    I've already discussed that, so I'll leave it as an
  2084.    exercise-- or, just see the BasWiz source code! The polygon
  2085.    routines are primarily written in BASIC.
  2086.  
  2087.  
  2088.  
  2089. Flower Drawing:
  2090.  
  2091.    This sort of thing would be rather difficult to do using
  2092.    strictly Cartesian methods, but with Polar coordinates, no
  2093.    problem. Here we calculate the radius based on the angle,
  2094.    using something like:
  2095.  
  2096.       FOR Angle! = 0 TO PI! * 2 STEP .01
  2097.  
  2098.    (a low STEP value is a good idea). The radius is calculated
  2099.    like so:
  2100.  
  2101.       Radius! = TotalRadius! * COS(Petals! * Angle!)
  2102.  
  2103.    The Petals! value specifies how many petals the flower should
  2104.    have. If it is odd, the exact number of petals will be
  2105.    generated; if even, twice that number will be generated.
  2106.  
  2107.    These figures are technically called "roses", although they
  2108.    more resemble daisies. Try the ROSES.BAS program to see how
  2109.    they look.
  2110.  
  2111.  
  2112.  
  2113. Other Drawing:
  2114.  
  2115.    Experiment! There are all sorts of interesting things you can
  2116.    do with the Polar coordinate system in particular. Dig up
  2117.    those old Geometry texts or see if your Calculus books review
  2118.    it. If you've kept well away from math, try your local
  2119.    library or used book store.
  2120.  
  2121.                Memory Management and Pointers          page 44
  2122.  
  2123.  
  2124.  
  2125. On the whole, BASIC is easily a match for any other language, as
  2126. far as general-purpose programming goes. There is one major
  2127. lack, however-- a set of valuable features that is supported by
  2128. most other languages, but was inexplicably left out of BASIC.
  2129. Perhaps Microsoft felt it was too advanced and dangerous for a
  2130. so-called "beginner's" language. In truth, using pointers and
  2131. memory management takes a little understanding of what you're
  2132. doing-- the compiler can't protect you from all of your
  2133. mistakes. However, they can be extraordinarily useful for many
  2134. things, so I have added these capabilities to BasWiz.
  2135.  
  2136. A "pointer" is essentially just the address of an item. It is
  2137. useful in two respects: it allows you to pass just the pointer,
  2138. rather than the whole item (be it a TYPEd variable, normal
  2139. variable, entire array, or whatever) to a subprogram. This is
  2140. faster and more memory-efficient than the alternatives.
  2141. Secondly, a pointer combined with memory management allows you
  2142. to allocate and deallocate memory "on the fly", in just the
  2143. amount you need. You don't have to worry about DIMensioning an
  2144. array too large or too small, or even with how large each
  2145. element of the array should be, for example. You can determine
  2146. that when your program -runs-, rather than at compile time, and
  2147. set up your data structures accordingly. You can also create a
  2148. large variety of data structures, such as trees and linked
  2149. lists, which would be difficult and cumbersome to emulate using
  2150. BASIC alone.
  2151.  
  2152. The BasWiz memory/pointer routines allow you to allocate and
  2153. deallocate memory; fill, copy or move a block of memory; get or
  2154. put a single character according to a pointer; and convert back
  2155. and forth between a segment/offset address and a pointer.
  2156.  
  2157. Pointers are kept in LONG integers, using an absolute memory
  2158. addressing scheme. This means that you can manipulate pointers
  2159. just like any ordinary LONG integer, e.g. to move to the next
  2160. memory address, just add one. Since you can convert from a
  2161. segment/offset address to a pointer and you can copy information
  2162. from one pointer to another, you can move information back and
  2163. forth between allocated memory and a TYPEd variable, numeric
  2164. variable, or array. You can even do things like set a pointer to
  2165. screen memory and transfer the screen into a variable or vice
  2166. versa! Or implement your own "far string" routines, hierarchical
  2167. evaluations, or any number of other things. Pointers are
  2168. incredibly powerful!
  2169.  
  2170.                Memory Management and Pointers          page 45
  2171.  
  2172.  
  2173.  
  2174. Note that there are different ways of representing the same
  2175. segment/offset address, but only one absolute pointer
  2176. representation. If you need to compare two addresses, using
  2177. pointers is terrific. However, it's good to keep in mind that an
  2178. segment/offset address may -appear- to change if you convert it
  2179. to a pointer and then back to a segment/offset address. When you
  2180. convert from a pointer to a segment and offset, the segment will
  2181. be maximized and the offset will be minimized. So, for example,
  2182. 0040:001C will turn into 0041:000C.
  2183.  
  2184. Although the byte count for these routines is handled through a
  2185. LONG integer, the routines handle a maximum of 65,520 bytes at a
  2186. time. In other words, a pointer can only access a bit less than
  2187. 64K at a time. If I get enough requests to extend this range, I
  2188. will do so. Meantime, that's the limit!
  2189.  
  2190. There are two routines which take care of memory management.
  2191. These allow you to allocate or deallocate memory. Note that if
  2192. you allocate too much memory, QuickBasic won't have any memory
  2193. to work with! Use the BASIC function "SETMEM" to see how much
  2194. memory is available before going hog-wild.
  2195.  
  2196. You can allocate memory like so:
  2197.  
  2198.    MAllocate Bytes&, Ptr&, ErrCode%
  2199.  
  2200. If there isn't enough memory available, an error code will be
  2201. returned. Otherwise, Ptr& will point to the allocated memory.
  2202. Memory is allocated in chunks of 16 bytes, so there may be some
  2203. memory wasted if you choose a number of bytes that isn't evenly
  2204. divisible by 16.
  2205.  
  2206. When you are finished with that memory, you can free it up by
  2207. deallocation:
  2208.  
  2209.    MDeallocate Ptr&, ErrCode%
  2210.  
  2211. An error code will be returned if Ptr& doesn't point to
  2212. previously allocated memory.
  2213.  
  2214. In the best of all possible worlds, there would be a third
  2215. routine which would allow you to reallocate or resize a block of
  2216. memory. However, due to certain peculiarities of QuickBasic, I
  2217. was unable to implement that. You can simulate such a thing by
  2218. allocating a new area of memory of the desired size, moving an
  2219. appropriate amount of information from the old block to the new,
  2220. and finally deallocating the old block.
  2221.  
  2222.                Memory Management and Pointers          page 46
  2223.  
  2224.  
  2225.  
  2226. Once you've allocated memory, you can move any sort of
  2227. information in or out of it except normal strings-- fixed-length
  2228. strings, TYPEd values, arrays, or numeric values. To do that,
  2229. you use BASIC's VARSEG and VARPTR functions on the variable.
  2230. Convert the resulting segment/offset address to a pointer:
  2231.  
  2232.    TSeg% = VARSEG(Variable)
  2233.    TOfs% = VARPTR(Variable)
  2234.    VariablePtr& = MJoinPtr&(TSeg%, TOfs%)
  2235.  
  2236. Moving the information from one pointer to another is like so:
  2237.  
  2238.    MMove FromPtr&, ToPtr&, Bytes&
  2239.  
  2240. For STRING or TYPEd values, you can get the number of bytes via
  2241. the LEN function. For numeric values, the following applies:
  2242.  
  2243.    Type       Bytes per value
  2244.    =======    ===============
  2245.    INTEGER           2
  2246.    LONG              4
  2247.    SINGLE            4
  2248.    DOUBLE            8
  2249.  
  2250. The "memory move" (MMove) routine is good for more than just
  2251. transferring information between a variable and allocated
  2252. memory, of course. Pointers can refer to any part of memory. For
  2253. instance, CGA display memory starts at segment &HB800, offset 0,
  2254. and goes on for 4000 bytes in text mode. That gives a pointer of
  2255. &HB8000. You can transfer from the screen to a variable or vice
  2256. versa. For that matter, you can scroll the screen up, down,
  2257. left, or right by using the appropriate pointers. Add two to the
  2258. pointer to move it to the next character or 160 to move it to
  2259. the next row. Pointers have all kinds of applications! You don't
  2260. need to worry about overlapping memory-- if the two pointers,
  2261. combined with the bytes to move, overlap at some point, why, the
  2262. MMove routine takes care of that for you. It avoids pointer
  2263. conflicts. MMove is a very efficient memory copying routine.
  2264.  
  2265. Suppose you've got a pointer and would like to convert it back
  2266. to the segment/offset address that BASIC understands. That's no
  2267. problem:
  2268.  
  2269.    MSplitPtr Ptr&, TSeg%, TOfs%
  2270.  
  2271.                Memory Management and Pointers          page 47
  2272.  
  2273.  
  2274.  
  2275. You might also want to fill an area of memory with a specified
  2276. byte value, perhaps making freshly-allocated memory zeroes, for
  2277. example:
  2278.  
  2279.    MFill Ptr&, Value%, Bytes&
  2280.  
  2281. Finally, there may be occasions when you might want to transfer
  2282. a single character. Rather than going through putting the
  2283. character into a STRING*1, getting the VARSEG/VARPTR, and using
  2284. MJoinPtr&, there is a simpler way:
  2285.  
  2286.    MPutChr Ptr&, Ch$
  2287.    Ch$ = MGetChr$(Ptr&)
  2288.  
  2289. Hopefully, this will give you some ideas to start with. I'll
  2290. expand on the uses of pointers and give further examples in
  2291. future versions of BasWiz. There are many, many possible uses
  2292. for such capabilities. Pointers and memory management used to be
  2293. the only real way in which BASIC could be considered inferior to
  2294. other popular languages-- that is no more!
  2295.  
  2296. NOTE:
  2297.    QuickBasic may move its arrays around in memory! Don't expect
  2298.    the address of an array to remain constant while your program
  2299.    is running. Be sure to get the VARSEG/VARPTR for arrays any
  2300.    time you're not sure they're in the same location. Among the
  2301.    things which can cause arrays to move are use of DIM, REDIM,
  2302.    or ERASE, and SHELL. I'm not sure if anything else may cause
  2303.    the arrays to move, so be cautious!
  2304.  
  2305.                           Quick Timer                  page 48
  2306.  
  2307.  
  2308.  
  2309. On occasion, it's convenient to be able to time something
  2310. precisely, or delay for a very small interval. The standard PC
  2311. timer runs at about 18.2 ticks per second, which is enough for
  2312. some purposes. For other tasks, it can be like timing a race
  2313. with an hourglass. Fortunately, we can do a lot better.
  2314.  
  2315. The Quick Timer unit provides four countdown timers which work
  2316. with millisecond resolution. This is not compatible with BASIC
  2317. programs that use BEEP, PLAY, or SOUND statements, since BASIC
  2318. reprograms the system timer to handle sound effects. A set of
  2319. replacement sound routines provides similar capabilities,
  2320. though, so this will not present a problem unless you need music
  2321. to be played in the background. The current BasWiz sound handler
  2322. only plays in the foreground.
  2323.  
  2324. Before using any of the Quick Timer routines, you must install
  2325. and initialize the fast timer, like so:
  2326.  
  2327.    QTInit
  2328.  
  2329. It is *IMPORTANT* to shut down the fast timer before your
  2330. program exits! Otherwise, the computer will certainly crash in
  2331. short order. The shutdown may be done thusly:
  2332.  
  2333.    QTDone
  2334.  
  2335. Once the fast timer is installed, there are four countdown
  2336. channels available. You can set any of the channels to a given
  2337. value (0-32767), and it will count down to zero at 1000 ticks
  2338. per second. Channel 0 is used internally by several of the Quick
  2339. Timer routines, but channels 1-3 are entirely free for your use.
  2340. The "countdown timer" approach allows you to maintain timing in
  2341. the background while your program does something else.
  2342.  
  2343.    SetTimer Channel%, MilliSeconds%
  2344.    MilliSeconds% = GetTimer%(Channel%)
  2345.  
  2346. If your aim is to time something, set a channel to 32767 when it
  2347. starts, and get the channel value when it ends. Subtract the
  2348. final channel value from 32767 to get the number of milliseconds
  2349. taken by the event. You will not be able to time events that
  2350. last for more than some 32 seconds, since that is the maximum
  2351. delay the timer can handle.
  2352.  
  2353. If you just want to delay for a bit, without doing anything
  2354. else, it will be more convenient to use the QTDelay routine.
  2355.  
  2356.    QTDelay MilliSeconds%
  2357.  
  2358. Note that QTDelay uses channel 0. It simply sets the channel to
  2359. the desired delay and waits until the channel has counted down
  2360. to zero.
  2361.  
  2362.                           Quick Timer                  page 49
  2363.  
  2364.  
  2365.  
  2366. Since our Quick Timer reprograms the same timer than BASIC wants
  2367. to reprogram for sound handling, it is important to avoid the
  2368. use of any BASIC sound statements: BEEP, PLAY, or SOUND. BasWiz
  2369. provides replacements for these statements. Although the BasWiz
  2370. routines don't support background music processing, they can be
  2371. much smaller than the originals, especially if your program
  2372. doesn't use floating point math (which SOUND and PLAY normally
  2373. bring in, whether the rest of the program needs it or not).
  2374.  
  2375. All of the replacement sound routines make use of countdown
  2376. channel 0. You should generally avoid use of channel 0 by your
  2377. program to avoid possible conflicts.
  2378.  
  2379. The BEEP statement can be simply replaced:
  2380.  
  2381.    QTBeep
  2382.  
  2383. The SOUND statement takes a little more work to replace. Whereas
  2384. SOUND uses a sound time based on 18.2 ticks per second, QTSound
  2385. is based on milliseconds. When converting from SOUND to QTSound,
  2386. you must multiply the time by 55 to compensate.
  2387.  
  2388.    QTSound Frequency%, MilliSeconds%
  2389.  
  2390. The PLAY statement works just like you'd expect, although "MB"
  2391. (play music in the background) is ignored, since that capability
  2392. is not supported. Note that QTPlay will also ignore any errors
  2393. in the music command string-- this can be handy for interpreting
  2394. "ANSI" music, which may contain garbage. See the ANSI.BAS file,
  2395. which contains a "BBS ANSI" interpreter.
  2396.  
  2397.    QTPlay MusicCommand$
  2398.  
  2399. Remember, these BasWiz music routines are based on the Quick
  2400. Timer. You must install the Quick Timer with QTInit before they
  2401. will function. Don't forget to shut down with QTDone when you're
  2402. finished!
  2403.  
  2404.                       Telecommunications               page 50
  2405.  
  2406.  
  2407.  
  2408. BASIC is unusual among languages in that it comes complete with
  2409. built-in telecommunications support. Unfortunately, that support
  2410. is somewhat crude. Amongst other problems, it turns off the DTR
  2411. when the program SHELLs or ends, making it difficult to write
  2412. doors for BBSes or good terminal programs. It also requires use
  2413. of the /E switch for error trapping, since it generates errors
  2414. when line noise is encountered, and doesn't provide much
  2415. control. It doesn't even support COM3 and COM4, which have been
  2416. available for years.
  2417.  
  2418. BasWiz rectifies these troubles. It allows comprehensive control
  2419. over communications, includes COM3 and COM4, and doesn't require
  2420. error trapping. It won't fiddle with the DTR unless you tell it
  2421. to do so. The one limitation is that you may use only a single
  2422. comm port at a time.
  2423.  
  2424. Before you can use communications, you must initialize the
  2425. communications handler. If you didn't have BasWiz, you would
  2426. probably use something like:
  2427.  
  2428.    OPEN "COM1:2400,N,8,1,RS,CS,DS" AS #1
  2429.  
  2430. With BasWiz, you do not have to set the speed, parity, and so
  2431. forth. Communications will proceed with whatever the current
  2432. settings are, unless you choose to specify your own settings.
  2433. When you initialize the comm handler, you specify only the port
  2434. number (1-4) and the size of the input and output buffers
  2435. (1-32,767 bytes):
  2436.  
  2437.    TCInit Port, InSize, OutSize, ErrCode
  2438.  
  2439. The size you choose for the buffers should be guided by how your
  2440. program will use communications. Generally, a small output
  2441. buffer of 128 bytes will be quite adequate. You may wish to
  2442. expand it up to 1,500 bytes or so if you expect to write file
  2443. transfer protocols. For the input buffer, you will want perhaps
  2444. 512 bytes for normal use. For file transfer protocols, perhaps
  2445. 1,500 bytes would be better. If a high baud rate is used, or for
  2446. some other reason you might not be emptying the buffer
  2447. frequently, you may wish to expand the input buffer size to
  2448. 4,000 bytes or more.
  2449.  
  2450. When you are done with the telecomm routines, you must shut them
  2451. down. In BASIC, this would look something like:
  2452.  
  2453.    CLOSE #1
  2454.  
  2455. With the BasWiz routines, though, you would use this instead:
  2456.  
  2457.    TCDone
  2458.  
  2459.                      Telecommunications                page 51
  2460.  
  2461.  
  2462.  
  2463. The BasWiz "TCDone" does not drop the DTR, unlike BASIC's
  2464. "CLOSE". This means that the modem will not automatically be
  2465. told to hang up. With BasWiz, you have complete control over the
  2466. DTR with the TCDTR routine. Use a value of zero to drop the DTR
  2467. or nonzero to raise the DTR:
  2468.  
  2469.    TCDTR DTRstate
  2470.  
  2471. You may set the speed of the comm port to any baud rate from
  2472. 1-65,535. If you will be dealing with comm programs that were
  2473. not written using BasWiz, you may wish to restrict that to the
  2474. more common rates: 300, 1200, 2400, 4800, 9600, 19200, 38400,
  2475. and 57600.
  2476.  
  2477.    TCSpeed Baud&
  2478.  
  2479. The parity, word length, and stop bits can also be specified.
  2480. You may use 1-2 stop bits, 6-8 bit words, and parity settings of
  2481. None, Even, Odd, Mark, or Space. Nearly all BBSes use settings
  2482. of None, 8 bit words, and 1 stop bit, although you will
  2483. sometimes see Even, 7 bit words, and 1 stop bit. The other
  2484. capabilities are provided for dealing with mainframes and other
  2485. systems which may require unusual communications parameters.
  2486.  
  2487. When specifying parity, only the first character in the string
  2488. is used, and uppercase/lowercase distinctions are ignored. Thus,
  2489. using either "none" or "N" would specify that no parity is to be
  2490. used.
  2491.  
  2492.    TCParms Parity$, WordLength, StopBits
  2493.  
  2494. If your program needs to be aware of when a carrier is present,
  2495. it can check the carrier detect signal from the modem with the
  2496. TCCarrier function. This function returns zero if no carrier is
  2497. present:
  2498.  
  2499.    IF TCCarrier THEN
  2500.       PRINT "Carrier detected"
  2501.    ELSE
  2502.       PRINT "No carrier"
  2503.    END IF
  2504.  
  2505.                      Telecommunications                page 52
  2506.  
  2507.  
  2508.  
  2509. Suppose, though, that you need to know immediately when someone
  2510. has dropped the carrier? It wouldn't be too convenient to have
  2511. to spot TCCarrier functions all over your program! In that case,
  2512. try the "ON TIMER" facility provided by BASIC for keeping an eye
  2513. on things. It will enable you to check the carrier at specified
  2514. intervals and act accordingly. Here's a brief framework for
  2515. writing such code:
  2516.  
  2517.    ON TIMER(30) GOSUB CarrierCheck
  2518.    TIMER ON
  2519.    ' ...your program goes here...
  2520. CarrierCheck:
  2521.    IF TCCarrier THEN     ' if the carrier is present...
  2522.       RETURN             ' ...simply resume where we left off
  2523.    ELSE                  ' otherwise...
  2524.       RETURN Restart     ' ...return to the "Restart" label
  2525.    END IF
  2526.  
  2527. To get a character from the comm port, use the TCInkey$
  2528. function:
  2529.  
  2530.    ch$ = TCInkey$
  2531.  
  2532. To send a string to the comm port, use TCWrite:
  2533.  
  2534.    TCWrite St$
  2535.  
  2536. If you are dealing strictly with text, you may want to have a
  2537. carriage return and a linefeed added to the end of the string.
  2538. No problem:
  2539.  
  2540.    TCWriteLn St$
  2541.  
  2542. Note that the length of the output buffer affects how the
  2543. TCWrite and TCWriteLn routines work. They don't actually send
  2544. string directly to the comm port. Instead, they put the string
  2545. into the output buffer, and it gets sent to the comm port
  2546. whenever the comm port is ready. If there is not enough room in
  2547. the output buffer for the whole string, the TCWrite/TCWriteLn
  2548. routines are forced to wait until enough space has been cleared
  2549. for the string. This can delay your program. You can often avoid
  2550. this delay simply by making the output buffer larger.
  2551.  
  2552. If you'd like to know how many bytes are waiting in the input
  2553. buffer or output buffer, there are functions which will tell
  2554. you:
  2555.  
  2556.    PRINT "Bytes in input buffer:"; TCInStat
  2557.    PRINT "Bytes in output buffer:"; TCOutStat
  2558.  
  2559.                      Telecommunications                page 53
  2560.  
  2561.  
  2562.  
  2563. If you would like to clear the buffers for some reason, you can
  2564. do that too. The following routines clear the buffers,
  2565. discarding anything which was waiting in them:
  2566.  
  2567.    TCFlushIn
  2568.    TCFlushOut
  2569.  
  2570. Finally, there is a routine which allows you to handle ANSI
  2571. codes in a window. Besides the IBM semi-ANSI display code
  2572. subset, mock-ANSI music is allowed. This routine is designed as
  2573. a subroutine that you can access via GOSUB, since there are a
  2574. number of variables that the routine needs to maintain that
  2575. would be a nuisance to pass as parameters, and QuickBasic
  2576. unfortunately can't handle SUBs in $INCLUDE files (so SHARED
  2577. won't work). To use it, either include ANSI.BAS directly in your
  2578. code, or use:
  2579.  
  2580.    REM $INCLUDE: 'ANSI.BAS'
  2581.  
  2582. Set St$ to the string to process, set Win% to the handle of the
  2583. window to which to display, and set Music% to zero if you don't
  2584. want sounds or -1 if you do want sounds. Then:
  2585.  
  2586.    GOSUB ANSIprint
  2587.  
  2588. Note that the virtual screen tied to the window must be at least
  2589. an 80 column by 25 row screen, since ANSI expects that size. You
  2590. are also advised to have an ON ERROR trap if you use ANSIprint
  2591. with Music% = -1, just in case a "bad" music sequence slips
  2592. through and makes BASIC unhappy. Check for ERR = 5 (Illegal
  2593. Function Call). I may add a music handler later to avoid this.
  2594.  
  2595. To get some idea of how these routines all tie together in
  2596. practice, see the TERM.BAS example program. It provides a simple
  2597. "dumb terminal" program to demonstrate the BasWiz comm handler.
  2598. Various command-line switches are allowed:
  2599.  
  2600.    /43     use 43-line mode (EGA and VGA only)
  2601.    /COM2   use COM2
  2602.    /COM3   use COM3
  2603.    /COM4   use COM4
  2604.    /300    use 300 bps
  2605.    /1200   use 1200 bps
  2606.    /9600   use 9600 bps
  2607.    /14400  use 14400 bps
  2608.    /38400  use 38400 bps
  2609.    /57600  use 57600 bps
  2610.    /QUIET  ignore "ANSI" music
  2611.  
  2612. By default, the TERM.BAS program will use COM1 at 2400 baud with
  2613. no parity, 8 bit words and 1 stop bit. You can exit the program
  2614. by pressing Alt-X.
  2615.  
  2616.                      Telecommunications                page 54
  2617.  
  2618.  
  2619.  
  2620. If you're using a fast modem (9600 bps or greater), you should
  2621. turn on hardware flow control for reliable communications:
  2622.  
  2623.    TCFlowCtl -1
  2624.  
  2625. The Xmodem file transfer protocol is currently supported for
  2626. sending files only. It automatically handles any of the usual
  2627. variants on the Xmodem protocol: 128-byte or 1024-byte blocks,
  2628. plus checksum or CRC error detection. In other words, it is
  2629. compatible with Xmodem (checksum), Xmodem CRC, and Xmodem-1K
  2630. (single-file Ymodem-like variant).
  2631.  
  2632. There are only two routines which must be used to transfer a
  2633. file. The first is called once to initialize the transfer. The
  2634. second is called repeatedly until the transfer is finished or
  2635. aborted. Complete status information is returned by both
  2636. routines. You can ignore most of this information or display it
  2637. any way you please.
  2638.  
  2639. The initialization routine looks like this:
  2640.  
  2641.    StartXmodemSend Handle, Protocol$, Baud$, MaxRec, Record,
  2642.       EstTime$, ErrCode
  2643.  
  2644. Only the first three parameters are passed to the routine. These
  2645. are the Handle of the file that you wish to send (use FOpen to
  2646. get the handle) and the Protocol$ that you wish to use ("Xmodem"
  2647. or "Xmodem-1K"), and the current Baud$. On return, you will get
  2648. an ErrCode if the other computer did not respond, or MaxRec (the
  2649. number of blocks to be sent), Record (the current block number),
  2650. and EstTime$ (an estimate of the time required to complete the
  2651. transfer. The Protocol$ will have "CHK" or "CRC" added to it to
  2652. indicate whether checksum or CRC error detection is being used,
  2653. depending on which the receiver requested.
  2654.  
  2655. The secondary routine looks like this:
  2656.  
  2657.    XmodemSend Handle, Protocol$, MaxRec, Record, ErrCount,
  2658.       ErrCode
  2659.  
  2660. The ErrCode may be zero (no error), greater than zero (error
  2661. reading file), or less than zero (file transfer error,
  2662. completion or abort). See the appendix on Error Codes for
  2663. specific details. The TERM.BAS example program shows how these
  2664. routines work together in practice.
  2665.  
  2666. The file accessed by the Xmodem routine will remain open.
  2667. Remember to close it when the transfer is done (for whatever
  2668. reason), using the FClose routine.
  2669.  
  2670.                      Telecommunications                page 55
  2671.  
  2672.  
  2673.  
  2674. A few notes on the ins and outs of telecommunications...
  2675.  
  2676. The DTR signal is frequently used to control the modem. When the
  2677. DTR is "raised" or "high", the modem knows that we're ready to
  2678. do something. When the DTR is "dropped" or "low", the modem
  2679. knows that we're not going to do anything. In most cases, this
  2680. tells it to hang up or disconnect the phone line. Some modems
  2681. may be set to ignore the DTR, in which case it will not
  2682. disconnect when the DTR is dropped. Usually this can be fixed by
  2683. changing a switch on the modem. On some modems, a short software
  2684. command may suffice.
  2685.  
  2686. The DTR is generally the best way to disconnect. The Hayes "ATH"
  2687. command is supposed to hang up, but it doesn't work very well.
  2688.  
  2689. The BasWiz comm handler makes sure the DTR is raised when TCInit
  2690. is used. It does not automatically drop the DTR when TCDone is
  2691. used, so you can keep the line connected in case another program
  2692. wants to use it. If this is not suitable, just use TCDTR to drop
  2693. the DTR. Your program must always use TCDone before it exits,
  2694. but it need only drop the DTR if you want it that way.
  2695.  
  2696. If you want to execute another program via SHELL, it is ok to
  2697. leave communications running as long as control will return to
  2698. your program when the SHELLed program is done. In that case, the
  2699. input buffer will continue to receive characters from the comm
  2700. port unless the SHELLed program provides its own comm support.
  2701. The output buffer will likewise continue to transmit characters
  2702. unless overruled.
  2703.  
  2704. An assortment of file transfer protocols will be provided in
  2705. future versions of BasWiz. Among the ones supported will be
  2706. Xmodem, Xmodem-1K, Ymodem (batch), and Modem7 (batch). I do not
  2707. expect to support Kermit or Zmodem, since they are unduly
  2708. complicated. You can handle any file transfer protocol you like
  2709. by SHELLing to an external protocol program, or of course you
  2710. can write your own support code.
  2711.  
  2712.                 The Virtual Windowing System           page 56
  2713.  
  2714.  
  2715.  
  2716. The virtual windowing system offers pop-up and collapsing
  2717. windows, yes... but that is just a small fraction of what it
  2718. provides. When you create a window, the part that you see on the
  2719. screen may be only a view port on a much larger window, called a
  2720. virtual screen. You can make virtual screens of up to 255 rows
  2721. long or 255 columns wide. The only limitation is that any single
  2722. virtual screen must take up less than 65,520 bytes. Each virtual
  2723. screen is treated much like the normal screen display, with
  2724. simple replacements for the standard PRINT, LOCATE, and COLOR
  2725. commands. Many other commands are provided for additional
  2726. flexibility. The window on the virtual screen may be moved,
  2727. resized, or requested to display a different portion of the
  2728. virtual screen. If you like, you may choose to display a frame
  2729. and/or title around a window. When you open a new window, any
  2730. windows under it are still there and can still be updated--
  2731. nothing is ever destroyed unless you want it that way! With the
  2732. virtual windowing system, you get a tremendous amount of control
  2733. for a very little bit of work.
  2734.  
  2735. The current version of the virtual windowing system only allows
  2736. text mode screens to be used. All standard text modes are
  2737. supported, however. This includes 25x40 CGA screens, the
  2738. standard 25x80 screen, and longer screens such as the 43x80 EGA
  2739. screen. The virtual windowing system is designed for computers
  2740. that offer hardware-level compatibility with the IBM PC, which
  2741. includes almost all MS-DOS/PC-DOS computers in use today.
  2742.  
  2743.  
  2744. Terminology:
  2745. -----------
  2746.  
  2747. DISPLAY
  2748.    The actual screen.
  2749.  
  2750. SHADOW SCREEN
  2751.    This is a screen kept in memory which reflects any changes
  2752.    you make to windows. Rather than making changes directly on
  2753.    the actual screen, the virtual windowing system works with a
  2754.    "shadow screen" for increased speed and flexibility. You
  2755.    specify when to update the display from the shadow screen.
  2756.    This makes changes appear very smoothly.
  2757.  
  2758. VIRTUAL SCREEN
  2759.    This is a screen kept in memory which can be treated much
  2760.    like the actual screen. You may choose to make a virtual
  2761.    screen any reasonable size. Every virtual screen will have a
  2762.    corresponding window.
  2763.  
  2764. WINDOW
  2765.    This is the part of a virtual screen which is actually
  2766.    displayed. You might think of a window as a "view port" on a
  2767.    virtual screen. A window may be smaller than its virtual
  2768.    screen or the same size. It may have a frame or a title and
  2769.    can be moved or resized.
  2770.  
  2771.                 The Virtual Windowing System           page 57
  2772.  
  2773.  
  2774.  
  2775. Frankly, the virtual windowing system is one of those things
  2776. that's more difficult to explain than to use. It's very easy to
  2777. use, as a matter of fact, but the basic concepts will need a
  2778. little explanation. Rather than launching into a tedious and
  2779. long-winded description of the system, I'm going to take a more
  2780. tutorial approach, giving examples and explaining as I go along.
  2781. Take a look at the WDEMO.BAS program for examples.
  2782.  
  2783. Let's begin with the simplest possible scenario, where only a
  2784. background window is created. This looks just like a normal
  2785. screen.
  2786.  
  2787.    REM $INCLUDE: 'BASWIZ.BI'
  2788.    DEFINT A-Z
  2789.    Rows = 25: Columns = 80         ' define display size
  2790.    WInit Rows, Columns, ErrCode    ' initialize window system
  2791.    IF ErrCode THEN                 ' stop if we couldn't...
  2792.       PRINT "Insufficient memory"
  2793.       END
  2794.    END IF
  2795.    Handle = 0                      ' use background handle
  2796.    WWriteLn Handle, "This is going on the background window."
  2797.    WWriteLn Handle, "Right now, that's the full screen."
  2798.    WUpdate                         ' update the display
  2799.    WDone                           ' terminate window system
  2800.  
  2801. What we just did was to display two lines on the screen--
  2802. nothing at all fancy, but it gives you the general idea of how
  2803. things work. Let's take a closer look:
  2804.  
  2805.   - We INCLUDE the BASWIZ.BI definition file to let BASIC know
  2806.     that we'll be using the BasWiz routines.
  2807.  
  2808.   - We define the size of the display using the integer
  2809.     variables Rows and Columns (you can use any variable names
  2810.     you want). If you have an EGA display and had previously
  2811.     used WIDTH ,43 to go into 43x80 mode, you'd use "Rows = 43"
  2812.     here, for example.
  2813.  
  2814.   - We initialize the windowing system with WInit, telling it
  2815.     how large the display is. It returns an error code if it is
  2816.     unable to initialize.
  2817.  
  2818.   - We define the Handle of the window that we want to use. The
  2819.     "background window" is always available as handle zero, so
  2820.     we choose "Handle = 0".
  2821.  
  2822.   - We print two strings to the background window with WWriteLn,
  2823.     which is like a PRINT without a semicolon on the end (it
  2824.     moves to the next line).
  2825.  
  2826.   - At this point, only the shadow screen has been updated.
  2827.     We're ready to display the information, so we use WUpdate to
  2828.     update the actual screen.
  2829.  
  2830.   - We're all done with the program, so we end with WDone.
  2831.  
  2832.                 The Virtual Windowing System           page 58
  2833.  
  2834.  
  2835.  
  2836. See, there's nothing to it! We initialize the screen, print to
  2837. it or whatever else we need to do, tell the windowing system to
  2838. update the display, and when the program is done, we close up
  2839. shop.
  2840.  
  2841. The background screen is always available. It might help to
  2842. think of it as a virtual screen that's the size of the display.
  2843. The window on this virtual screen is exactly the same size, so
  2844. the entire virtual screen is displayed. As with other virtual
  2845. screens, you can print to it without disturbing anything else.
  2846. That means you can treat the background screen the same way
  2847. regardless of whether it has other windows on top of it-- the
  2848. other windows just "cover" the background information, which
  2849. will still be there.
  2850.  
  2851. This leads us to the topic of creating windows. Both a virtual
  2852. screen and a window are created simultaneously-- remember, a
  2853. window is just a view port on a virtual screen. The window can
  2854. be the same size as the virtual screen, in which case the entire
  2855. virtual screen is visible (as with the background window) or it
  2856. can be smaller than the virtual screen, in which case just a
  2857. portion of the virtual screen will be visible at any one time.
  2858.  
  2859. A window is created like so:
  2860.  
  2861.    ' This is a partial program and can be inserted in the
  2862.    ' original example after the second WWriteLn statement...
  2863.    VRows = 43: VColumns = 80      ' define virtual screen size
  2864.    ' create the window
  2865.    WOpen VRows, VColumns, 1, 1, Rows, Columns, Handle, ErrCode
  2866.    IF ErrCode THEN                ' error if we couldn't...
  2867.       PRINT "Insufficient memory available"
  2868.       WDone                       ' (or use an error handler)
  2869.       END
  2870.    END IF
  2871.  
  2872. What we have done here is to create a virtual screen of 43 rows
  2873. by 80 columns. The window will be the size of the display, so if
  2874. you are in the normal 25x80 mode, only the first 25 rows of the
  2875. virtual screen will be visible. If you have an EGA or VGA in
  2876. 43x80 mode, though, the entire virtual screen will be visible!
  2877. So, this window lets you treat a screen the same way regardless
  2878. of the display size.
  2879.  
  2880. The Handle returned is used any time you want to print to this
  2881. new window or otherwise deal with it. If you are using many
  2882. windows, you might want to keep an array of handles, to make it
  2883. easier to keep track of which is which.
  2884.  
  2885.                 The Virtual Windowing System           page 59
  2886.  
  2887.  
  2888.  
  2889. By default, a virtual screen is created with the following
  2890. attributes:
  2891.  
  2892.   - The cursor is at (1,1), the upper left corner of the
  2893.     virtual screen.
  2894.   - The cursor size is 0 (invisible).
  2895.   - The text color is 7,0 (white foreground on a black
  2896.     background).
  2897.   - There is no title or frame.
  2898.   - The window starts at (1,1) in the virtual screen, which
  2899.     displays the area starting at the upper left corner of
  2900.     the virtual screen.
  2901.  
  2902. When you create a new window, it becomes the "top" window, and
  2903. will be displayed on top of any other windows that are in the
  2904. same part of the screen. Remember, you can print to a window or
  2905. otherwise deal with it, even if it's only partially visible or
  2906. entirely covered by other windows.
  2907.  
  2908. Don't forget WUpdate! None of your changes are actually
  2909. displayed until WUpdate is used. You can make as many changes as
  2910. you like before calling WUpdate, which will display the results
  2911. smoothly and at lightning speed.
  2912.  
  2913. We've created a window which is exactly the size of the display,
  2914. but which might well be smaller than its virtual screen. Let's
  2915. assume that the normal 25x80 display is being used, in which
  2916. case our virtual screen (43x80) is larger than the window. We
  2917. can still print to the virtual screen normally, but if we print
  2918. below line 25, the results won't be displayed. What a
  2919. predicament! How do we fix this?
  2920.  
  2921. The window is allowed to start at any given location in the
  2922. virtual screen, so if we want to see a different portion of the
  2923. virtual screen, all we have to do is tell the window to start
  2924. somewhere else. When the window is created, it starts at the
  2925. beginning of the virtual screen, coordinate (1,1). The WView
  2926. routine allows us to change this.
  2927.  
  2928. In our example, we're displaying a 43x80 virtual screen in a
  2929. 25x80 window. To begin with, then, rows 1-25 of the virtual
  2930. screen are visible. To make rows 2-26 of the virtual screen
  2931. visible, we simply do this:
  2932.  
  2933.    WView Handle, 2, 1
  2934.  
  2935. That tells the window to start at row 2, column 1 in the virtual
  2936. screen. Sounds easy enough, doesn't it? Well, if not, don't
  2937. despair. Play with it a little until you get the hang of it.
  2938.  
  2939.                 The Virtual Windowing System           page 60
  2940.  
  2941.  
  2942.  
  2943. You've noticed that the window doesn't need to be the same size
  2944. as the virtual screen. Suppose we don't want it the same size as
  2945. the display, either... suppose we want it in a nice box, sitting
  2946. out of the way in a corner of the display? Well, we could have
  2947. created it that way to begin with when we used WOpen. Since
  2948. we've already created it, though, let's take a look at the
  2949. routines to change the size of a window and to move it
  2950. elsewhere. The window can be made as small as 1x1 or as large as
  2951. its virtual screen, and it can be moved anywhere on the display
  2952. you want it.
  2953.  
  2954. Let's make the window a convenient 10 rows by 20 columns:
  2955.  
  2956.    WSize Handle, 10, 20
  2957.  
  2958. And move it into the lower right corner of the display:
  2959.  
  2960.    WPlace Handle, 12, 55
  2961.  
  2962. Don't forget to call WUpdate or the changes won't be visible!
  2963. Note also that we didn't really lose any text. The virtual
  2964. screen, which holds all the text, is still there. We've just
  2965. changed the size and position of the window, which is the part
  2966. of the virtual screen that we see, so less of the text (if there
  2967. is any!) is visible. If we made the window larger again, the
  2968. text in the window would expand accordingly.
  2969.  
  2970. If you were paying close attention, you noticed that we didn't
  2971. place the resized window flush against the corner of the
  2972. display. We left a little bit of room so we can add a frame and
  2973. a title. Let's proceed to do just that.
  2974.  
  2975. Window frames are displayed around the outside of a window and
  2976. will not be displayed unless there is room to do so. We have
  2977. four different types of standard frames available:
  2978.  
  2979.    0   (no frame)
  2980.    1   single lines
  2981.    2   double lines
  2982.    3   single horizontal lines, double vertical lines
  2983.    4   single vertical lines, double horizontal lines
  2984.  
  2985. We must also choose the colors for the frame. It usually looks
  2986. best if the background color is the same background color as
  2987. used by the virtual screen. Let's go ahead and create a
  2988. double-line frame in bright white on black:
  2989.  
  2990.    FType = 2: Fore = 15: Back = 0
  2991.    WFrame Handle, FType, Fore, Back
  2992.  
  2993.                 The Virtual Windowing System           page 61
  2994.  
  2995.  
  2996.  
  2997. If you'd rather not use the default frame types, there's ample
  2998. room to get creative! Frames 5-9 can be defined any way you
  2999. please. They are null by default. To create a new frame type,
  3000. you must specify the eight characters needed to make the frame:
  3001. upper left corner, upper middle columns, upper right corner,
  3002. left middle rows, right middle rows, lower left corner, lower
  3003. middle columns, and lower right corner.
  3004.  
  3005.    +----------------------------------------+
  3006.    |  Want a plain text frame like this?    |
  3007.    |  Use the definition string "+-+||+-+"  |
  3008.    +----------------------------------------+
  3009.  
  3010. The above window frame would be defined something like this:
  3011.  
  3012.    Frame = 5
  3013.    FrameInfo$ = "+-+||+-+"
  3014.    WUserFrame Frame, FrameInfo$
  3015.  
  3016. Of course, you can choose any values you like. As always, the
  3017. names of the variables can be anything, as long as you name them
  3018. consistently within your program. You can even use constants if
  3019. you prefer:
  3020.  
  3021.    WUserFrame 5, "+-+||+-+"
  3022.  
  3023. If you use a frame, you can also have a "shadow", which provides
  3024. a sort of 3-D effect. The shadow can be made up of any character
  3025. you choose, or it can be entirely transparent, in which case
  3026. anything under the shadow will change to the shadow colors. This
  3027. latter effect can be quite nice. I've found that it works best
  3028. for me when I use a dim foreground color with a black
  3029. background-- a foreground color of 8 produces wonderful effects
  3030. on machines that support it (it's "bright black", or dark gray;
  3031. some displays will show it as entirely black, though, so it may
  3032. not always work the way you want). For a transparent shadow,
  3033. select CHR$(255) as the shadow character. You can turn the
  3034. shadow off with either a null string or CHR$(0).
  3035.  
  3036.    Shadow$ = CHR$(255)                  ' transparent shadow
  3037.    Fore = 8: Back = 0                   ' dark gray on black
  3038.    WShadow Handle, Shadow$, Fore, Back
  3039.  
  3040. A shadow will only appear if there is also a frame, and if there
  3041. is enough space for it on the screen. Currently, there is only
  3042. one type of shadow, which appears on the right and bottom sides
  3043. of the frame. It effectively makes the frame wider and longer by
  3044. one character.
  3045.  
  3046.                 The Virtual Windowing System           page 62
  3047.  
  3048.  
  3049.  
  3050. We can have a title regardless of whether a frame is present or
  3051. not. Like the frame, the title is displayed only if there is
  3052. enough room for it. If the window is too small to accommodate
  3053. the full title, only the part of the title that fits will be
  3054. displayed. The maximum length of a title is 70 characters.
  3055. Titles have their own colors.
  3056.  
  3057.    Title$ = "Wonderful Window!"
  3058.    Fore = 0: Back = 7
  3059.    WTitle Handle, Title$, Fore, Back
  3060.  
  3061. To get rid of a title, just use a null title string, for
  3062. example:
  3063.  
  3064.    Title$ = ""
  3065.  
  3066. It may be convenient to set up a window that isn't always
  3067. visible-- say, for a help window, perhaps. The window could be
  3068. set up in advance, then shown whenever requested using just one
  3069. statement:
  3070.  
  3071.    WHide Handle, Hide
  3072.  
  3073. You can make a window invisible by using any nonzero value for
  3074. Hide, or make it reappear by setting Hide to zero. As always,
  3075. the change will only take effect after WUpdate is used.
  3076.  
  3077. When WWrite or WWriteLn gets to the end of a virtual screen,
  3078. they normally scroll the "screen" up to make room for more text.
  3079. This is usually what you want, of course, but there are
  3080. occasions when it can be a nuisance. The automatic scrolling can
  3081. be turned off or restored like so:
  3082.  
  3083.    WScroll Handle, AutoScroll
  3084.  
  3085. There are only a few more ways of dealing with windows
  3086. themselves. After that, I'll explain the different things you
  3087. can do with text in windows and how to get information about a
  3088. specific window or virtual screen.
  3089.  
  3090. If you have a lot of windows, one window may be on top of
  3091. another, obscuring part or all of the window(s) below. In order
  3092. to make sure a window is visible, all you need to do is to put
  3093. it on top, right? Hey, is this easy or what?!
  3094.  
  3095.    WTop Handle
  3096.  
  3097. You may also need to "unhide" the window if you used WHide on it
  3098. previously.
  3099.  
  3100.                 The Virtual Windowing System           page 63
  3101.  
  3102.  
  3103.  
  3104. Note that the background window will always be the background
  3105. window. You can't put handle zero, the background window, on
  3106. top. What? You say you need to do that?! Well, that's one of the
  3107. ways you can use the WCopy routine. WCopy copies one virtual
  3108. screen to another one of the same size:
  3109.  
  3110.    WCopy FromHandle, ToHandle
  3111.  
  3112. You can copy the background window (or any other window) to
  3113. another window. The new window can be put on top, resized,
  3114. moved, or otherwise spindled and mutilated. The WDEMO program
  3115. uses this trick.
  3116.  
  3117. We've been through how to open windows, print to them, resize
  3118. them and move them around, among other things. We've seen how to
  3119. put a frame and a title on a window and pop it onto the display.
  3120. If you're a fan of flashy displays, though, you'd probably like
  3121. to be able to make a window "explode" onto the screen or
  3122. "collapse" off. It's the little details like that which make a
  3123. program visually exciting and professional-looking. I wouldn't
  3124. disappoint you by leaving something fun like that out!
  3125.  
  3126. Since we're using a virtual windowing system rather than just a
  3127. plain ol' ordinary window handler, there's an extra benefit.
  3128. When a window explodes or collapses, it does so complete with
  3129. its title, frame, shadow, and even its text. This adds rather
  3130. nicely to the effect.
  3131.  
  3132. To "explode" a window, we just set up all its parameters the way
  3133. we normally would-- open the window, add a title or frame if we
  3134. like, print any text that we want displayed, and set the screen
  3135. position. Then we use WExplode to zoom the window from a tiny
  3136. box up to its full size:
  3137.  
  3138.    WExplode Handle
  3139.  
  3140. The "collapse" routine works similarly. It should be used only
  3141. when you are through with a window, because it closes the window
  3142. when it's done. The window is collapsed from its full size down
  3143. to a tiny box, then eliminated entirely:
  3144.  
  3145.    WCollapse Handle
  3146.  
  3147. Note that WExplode and WCollapse automatically use WUpdate to
  3148. update the display. You do not need to use WUpdate yourself and
  3149. you should make sure that the screen is the way you want it
  3150. displayed before you call either routine.
  3151.  
  3152.                 The Virtual Windowing System           page 64
  3153.  
  3154.  
  3155.  
  3156. The WCollapse and WExplode routines were written in BASIC, so
  3157. you can customize them just the way you want them.
  3158.  
  3159. That's it for the windows. We've been through all the "tricky
  3160. stuff". There are a number of useful things you can do with a
  3161. virtual screen, though, besides printing to it with WWriteLn.
  3162. Let's take a look at what we can do.
  3163.  
  3164. WWriteLn is fine if you want to use a "PRINT St$" sort of
  3165. operation. Suppose you don't want to move to a new line
  3166. afterward, though? In BASIC, you'd use something like "PRINT
  3167. St$;" (with a semicolon). With the virtual windowing system, you
  3168. use WWrite, which is called just like WWriteLn:
  3169.  
  3170.    WWrite Handle, St$
  3171.  
  3172. There are also routines that work like CLS, COLOR and LOCATE:
  3173.  
  3174.    WClear Handle
  3175.    WColor Handle, Fore, Back
  3176.    WLocate Handle, Row, Column
  3177.  
  3178. The WClear routine is not quite like CLS in that it does not
  3179. alter the cursor position. If you want the cursor "homed", use
  3180. WLocate.
  3181.  
  3182. Note that the coordinates for WLocate are based on the virtual
  3183. screen, not the window. If you move the cursor to a location
  3184. outside the view port provided by the window, it will disappear.
  3185. Speaking of disappearing cursors, you might have noticed that
  3186. our WLocate doesn't mimic LOCATE exactly: it doesn't provide for
  3187. controlling the cursor size. Don't panic! There's another
  3188. routine available for that:
  3189.  
  3190.    WCursor Handle, CSize
  3191.  
  3192. The CSize value may range from zero (in which case the cursor
  3193. will be invisible) to the maximum size allowed by your display
  3194. adapter. This will always be at least eight.
  3195.  
  3196. Now, since each virtual screen is treated much like the full
  3197. display, you may be wondering what happens if the cursor is "on"
  3198. in more than one window. Does that mean multiple cursors are
  3199. displayed? Well, no. That would get a little confusing! Only the
  3200. cursor for the top window is displayed. If you put a different
  3201. window on top, the cursor for that window will be activated and
  3202. the cursor for the old top window will disappear. The virtual
  3203. windowing system remembers the cursor information for each
  3204. window, but it only actually displays the cursor for the window
  3205. that's on top.
  3206.  
  3207.                 The Virtual Windowing System           page 65
  3208.  
  3209.  
  3210.  
  3211.  
  3212. In addition to the usual screen handling, the windowing system
  3213. provides a number of new capabilities which you may find very
  3214. handy. These include routines to insert and delete both
  3215. characters and rows, which is done at the current cursor
  3216. position within a selected virtual screen:
  3217.  
  3218.    WDelChr Handle
  3219.    WDelLine Handle
  3220.    WInsChr Handle
  3221.    WInsLine Handle
  3222.  
  3223. These routines can also be used for scrolling. Remember, the
  3224. display isn't updated until you use WUpdate, and then it's
  3225. updated all at once. You can use any of the routines multiple
  3226. times and the display will still be updated perfectly smoothly--
  3227. all the real work goes on behind the scenes!
  3228.  
  3229. Normally, the windowing system interprets control codes
  3230. according to the ASCII standard-- CHR$(7) beeps, CHR$(8) is a
  3231. backspace, and so forth. Sometimes you may want to print the
  3232. corresponding IBM graphics character instead, though... or maybe
  3233. you just don't use control codes and want a little more speed
  3234. out of the windowing system. You can turn control code handling
  3235. on or off for any individual window:
  3236.  
  3237.    WControl Handle, DoControl
  3238.  
  3239. When you are done with a virtual screen and no longer need it,
  3240. you can dispose of it like so:
  3241.  
  3242.    WClose Handle
  3243.  
  3244. All of the information that can be "set" can also be retrieved.
  3245. That's useful in general, of course, but it's also a great
  3246. feature for writing portable subprograms. You can create
  3247. subprograms that will work with any virtual screen, since it can
  3248. retrieve any information it needs to know about the virtual
  3249. screen or its window. That's power!
  3250.  
  3251.                 The Virtual Windowing System           page 66
  3252.  
  3253.  
  3254.  
  3255. Here is a list of the available window information routines:
  3256.  
  3257.    WGetColor Handle, Fore, Back
  3258.    ' gets the current foreground and background colors
  3259.  
  3260.    WGetControl Handle, DoControl
  3261.    ' gets whether control codes are interpreted
  3262.  
  3263.    WGetCursor Handle, CSize
  3264.    ' gets the cursor size
  3265.  
  3266.    WGetFrame Handle, Frame, Fore, Back
  3267.    ' gets the frame type and frame colors
  3268.  
  3269.    WGetLocate Handle, Row, Column
  3270.    ' gets the cursor position
  3271.  
  3272.    WGetPlace Handle, Row, Column
  3273.    ' gets the starting position of a window on the display
  3274.  
  3275.    WGetScroll Handle, AutoScroll
  3276.    ' gets the status of auto-scroll
  3277.    ' (scrolling at the end of a virtual screen)
  3278.  
  3279.    Shadow$ = SPACE$(1)
  3280.    WGetShadow Handle, Shadow$, Fore, Back
  3281.    ' gets the shadow character (CHR$(0) if there's no
  3282.    ' shadow) and colors
  3283.  
  3284.    WGetSize Handle, Rows, Columns
  3285.    ' gets the size of a window
  3286.  
  3287.    Title$ = SPACE$(70)
  3288.    WGetTitle Handle, Title$, TLen, Fore, Back
  3289.    Title$ = LEFT$(Title$, TLen)
  3290.    ' gets the title string (null if there's no title) and
  3291.    ' title colors
  3292.  
  3293.    WGetTop Handle
  3294.    ' gets the handle of the top window
  3295.  
  3296.    FrameInfo$ = SPACE$(8)
  3297.    WGetUFrame$ Frame, FrameInfo$
  3298.    ' gets the specification for a given user-defined frame
  3299.  
  3300.    WGetView Handle, Row, Column
  3301.    ' gets the starting position of a window within a
  3302.    ' virtual screen
  3303.  
  3304.    WGetVSize Handle, Rows, Columns
  3305.    ' gets the size of a virtual screen
  3306.  
  3307.    WHidden Handle, Hidden
  3308.    ' tells you whether a window is visible
  3309.  
  3310.                 The Virtual Windowing System           page 67
  3311.  
  3312.  
  3313.  
  3314. As well as displaying information in a window, you will
  3315. frequently want to allow for getting input from the user. Of
  3316. course, INKEY$ will still work fine, but that's not an effective
  3317. way of handling more than single characters. The virtual window
  3318. system includes a flexible string input routine which is a lot
  3319. more powerful:
  3320.  
  3321.    WInput Handle, Valid$, ExitCode$, ExtExitCode$,
  3322.       MaxLength, St$, ExitKey$
  3323.  
  3324. The Valid$ variable allows you to specify a list of characters
  3325. which may be entered. If you use a null string (""), any
  3326. character will be accepted.
  3327.  
  3328. ExitCode$ specifies the normal keys that can be used to exit
  3329. input. You'll probably want to use a carriage return, CHR$(13),
  3330. for this most of the time. You can also specify exit on extended
  3331. key codes like arrow keys and function keys via ExtExitCode$.
  3332.  
  3333. MaxLength is the maximum length of the string you want. Use zero
  3334. to get the longest possible string. The length may go up to the
  3335. width of the virtual screen, minus one character. The window
  3336. will be scrolled sideways as needed to accommodate the full
  3337. length of the string.
  3338.  
  3339. The St$ variable is used to return the entered string, but you
  3340. can also use it to pass a default string to the routine.
  3341.  
  3342. ExitKey$ returns the key that was used to exit input.
  3343.  
  3344. A fairly strong set of editing capabilities is available through
  3345. WInput. The editing keys can be overridden by ExitCode$ or
  3346. ExtExitCode$, but by default they include support for both the
  3347. cursor keypad and WordStar:
  3348.  
  3349.    Control-S   LeftArrow    move left once
  3350.    Control-D   RightArrow   move right once
  3351.    Control-V   Ins          insert <--> overstrike modes
  3352.    Control-G   Del          delete current character
  3353.    Control-H   Backspace    destructive backspace
  3354.                Home         move to the start of input
  3355.                End          move to the end of input
  3356.  
  3357.                 The Virtual Windowing System           page 68
  3358.  
  3359.  
  3360.  
  3361. Pop-up menus have become very popular in recent years.
  3362. Fortunately, they are a natural application for virtual windows!
  3363. BasWiz provides a pop-up menuing routine which allows you to
  3364. have as many as 255 choices-- the window will be scrolled
  3365. automatically to accommodate your "pick list", with a highlight
  3366. bar indicating the current selection.
  3367.  
  3368. The pop-up menu routine uses a window which you've already set
  3369. up, so you can use any of the normal window options-- frames,
  3370. titles, shadows, etc. You must provide a virtual screen large
  3371. enough to hold your entire pick list; the window itself can be
  3372. any size at all.
  3373.  
  3374. The pick list is passed to WMenuPopUp through a string array.
  3375. You can dimension this array in any range that suits you. The
  3376. returned selection will be the relative position in the array (1
  3377. for the first item, etc); if the menu was aborted, 0 will be
  3378. returned instead.
  3379.  
  3380. The current window colors will be used for the "normal" colors.
  3381. You specify the desired highlight colors when calling the pop-up
  3382. menu routine.
  3383.  
  3384.    Result = WMenuPopUp(Handle, PickList$(), HiFore, HiBack)
  3385.  
  3386. The mouse is not supported, since BasWiz does not yet have mouse
  3387. routines. However, scrolling can be accomplished with any of the
  3388. more common methods: up and down arrows, WordStar-type Control-E
  3389. and Control-X, or Lotus-type tab and backtab. The ESCape key can
  3390. be used to abort without choosing an option.
  3391.  
  3392. On exit, the menu window will remain in its final position, in
  3393. case you wish to pop up a related window next to it or something
  3394. similar. Since it's just an ordinary window, you can use WClose
  3395. or WCollapse if you prefer to get rid of it.
  3396.  
  3397. The WMenuPopUp routine was written in BASIC, so you will find it
  3398. easy to modify to your tastes. It was written with extra
  3399. emphasis on comments and clarity, since I know many people will
  3400. want to customize this routine!
  3401.  
  3402.                 The Virtual Windowing System           page 69
  3403.  
  3404.  
  3405.  
  3406. There are two more routines which allow the virtual windowing
  3407. system to work on a wide variety of displays: WFixColor and
  3408. WSnow.
  3409.  
  3410. Chances are, as a software developer you have a color display.
  3411. However, there are many people out there who have monochrome
  3412. displays, whether due to preference, a low budget, or use of
  3413. notebook-style computers with mono LCD or plasma screens.
  3414. WFixColor allows you to develop your programs in color while
  3415. still supporting monochrome systems. It tells the virtual
  3416. windowing system whether to keep the colors as specified or to
  3417. translate them to their monochrome equivalents:
  3418.  
  3419.    WFixColor Convert%
  3420.  
  3421. Set Convert% to zero if you want true color (default), or to any
  3422. other value if you want the colors to be translated to
  3423. monochrome. In the latter case, the translation will be done
  3424. based on the relative brightness of the foreground and
  3425. background colors. The result is guaranteed to be readable on a
  3426. monochrome system if it's readable on a color system. You should
  3427. check the results on your system to make sure that such things
  3428. as highlight bars still appear highlighted, however.
  3429.  
  3430. In the case of some of the older or less carefully designed CGA
  3431. cards, the high-speed displays of the virtual windowing system
  3432. can cause the display to flicker annoyingly. You can get rid of
  3433. the flicker at the expense of slowing the display:
  3434.  
  3435.    WSnow Remove%
  3436.  
  3437. Set Remove% to zero if there is no problem with "snow" or
  3438. flickering (default), or to any other value if you need "snow
  3439. removal". Using snow removal will slow down the display
  3440. substantially, which may be a problem if you update (WUpdate) it
  3441. frequently.
  3442.  
  3443. Note that you can't detect either of these cases automatically
  3444. with perfect reliability. Not all CGA cards have flicker
  3445. problems. Also, mono displays may be attached to CGA cards and
  3446. the computer won't know the difference. A VGA with a "paper
  3447. white" monitor may well think it has color, and will mostly act
  3448. like it, but some "color" combinations can be very difficult to
  3449. read. While you can self-configure the program to some extent
  3450. using the GetDisplay routine (see Other Routines), you should
  3451. also provide command-line switches so that the user can override
  3452. your settings. Microsoft generally uses "/B" to denote a
  3453. monochrome ("black and white") display, so you may want to
  3454. follow that as a standard.
  3455.  
  3456. Finally, by popular request, there is a routine which returns
  3457. the segment and offset of a virtual screen. This lets you do
  3458. things with a virtual screen that are not directly supported by
  3459. BasWiz. Virtual screens are laid out like normal text screens.
  3460.  
  3461.    WGetAddress Handle, WSeg, WOfs
  3462.  
  3463.                        Other Routines                  page 70
  3464.  
  3465.  
  3466.  
  3467. There are a number of routines for which I couldn't find a
  3468. specific category.
  3469.  
  3470. To see how much expanded memory is available, use the GetEMS
  3471. function. It'll return zero if there is no expanded memory
  3472. installed:
  3473.  
  3474.    PRINT "Kbytes of expanded memory:"; GetEMS
  3475.  
  3476. The GetDisplay routine tells what kind of display adapter is
  3477. active and whether it's hooked up to a color monitor. The only
  3478. time it can't detect the monitor type is on CGA setups (it
  3479. assumes "color"). It's a good idea to allow a "/B" switch for
  3480. your program so the user can specify if a monochrome monitor is
  3481. attached to a CGA.
  3482.  
  3483.    GetDisplay Adapter, Mono
  3484.    IF Mono THEN
  3485.       PRINT "Monochrome monitor"
  3486.    ELSE
  3487.       PRINT "Color monitor"
  3488.    END IF
  3489.    SELECT CASE Adapter
  3490.       CASE 1: PRINT "MDA"
  3491.       CASE 2: PRINT "Hercules"
  3492.       CASE 3: PRINT "CGA"
  3493.       CASE 4: PRINT "EGA"
  3494.       CASE 5: PRINT "MCGA"
  3495.       CASE 6: PRINT "VGA"
  3496.    END SELECT
  3497.  
  3498. The ScreenSize routine returns the number of rows and columns on
  3499. the display (text modes only):
  3500.  
  3501.    ScreenSize Rows%, Columns%
  3502.  
  3503.                      Miscellaneous Notes               page 71
  3504.  
  3505.  
  3506.  
  3507. The virtual windowing system allows up to 16 windows to be open
  3508. at a time, including the background window, which is opened
  3509. automatically. This is subject to available memory, of course.
  3510.  
  3511. The far string handler allows up to 65,535 strings of up to 255
  3512. characters each, subject to available memory. When the handler
  3513. needs additional memory for string storage, it allocates more in
  3514. blocks of 16 Kbytes. If that much memory is not available, an
  3515. "out of memory" error will be generated (BASIC error number 7).
  3516. You can check the size of the available memory pool using the
  3517. SETMEM function provided by QuickBasic.
  3518.  
  3519. The communications handler only allows one comm port to be used
  3520. at a time. This will change in a future version.
  3521.  
  3522. The file handler does not allow you to combine Write mode with
  3523. Text mode or input buffering. This will change in a future
  3524. version of BasWiz.
  3525.  
  3526. A certain lack of speed is inherent in BCD math, especially if
  3527. you require high precision. The division, root, and trig
  3528. routines in particular are quite slow. I'll attempt to improve
  3529. this in the future, but the routines are already fairly well
  3530. optimized, so don't expect miracles. Precision costs!
  3531.  
  3532. The fraction routines are much faster, but they have a much
  3533. smaller range. I'll have to do some experimenting on that. It
  3534. may prove practical to use a subset of the BCD routines to
  3535. provide an extended range for fractions without an unreasonable
  3536. loss in speed.
  3537.  
  3538. All routines are designed to be as bomb-proof as possible. If
  3539. you pass an invalid value to a routine which does not return an
  3540. error code, it will simply ignore the value.
  3541.  
  3542. The EGA graphics routines are designed for use with EGAs having
  3543. at least 256K RAM on board. They will not operate properly on
  3544. old 64K EGA systems.
  3545.  
  3546. Image loading (.MAC and .PCX) is quite slow. The bulk of the
  3547. code is in BASIC at this point, to make it easier for me to
  3548. extend the routines to cover other graphics modes. They will be
  3549. translated to assembly later.
  3550.  
  3551. The G#Write and G#WriteLn services support three different
  3552. fonts: 8x8, 8x14, and 8x16. The default font is always 8x8,
  3553. providing the highest possible text density. QuickBasic, on the
  3554. other hand, allows only one font with a text density of as close
  3555. to 80x25 as possible.
  3556.  
  3557.                      Miscellaneous Notes               page 72
  3558.  
  3559.  
  3560.  
  3561. The G#Write and G#WriteLn services interpret ASCII control
  3562. characters, i.e. CHR$(0) - CHR$(31), according to the more
  3563. standard handling used by DOS rather than the esoteric
  3564. interpretation offered by QuickBasic. This is not exactly a
  3565. limitation, but it could conceivably cause confusion if your
  3566. program happens to use these characters. The ASCII
  3567. interpretation works as follows:
  3568.  
  3569.     Code       Meaning
  3570.     ====       =======
  3571.       7        Bell       (sound a beep through the speaker)
  3572.       8        Backspace  (eliminate the previous character)
  3573.       9        Tab        (based on 8-character tab fields)
  3574.      10        LineFeed   (move down one line, same column)
  3575.      12        FormFeed   (clear the screen)
  3576.      13        Return     (move to the start of the row)
  3577.  
  3578. G#MirrorH will only work properly on images with byte alignment!
  3579. This means that the width of the image must be evenly divisible
  3580. by four if SCREEN 1 is used, or evenly divisible by eight if
  3581. SCREEN 2 is used.
  3582.  
  3583. The graphics routines provide little error checking and will not
  3584. do clipping (which ignores points outside the range of the
  3585. graphics mode). If you specify coordinates which don't exist,
  3586. the results will be unusual at best. Try to keep those values
  3587. within the proper range!
  3588.  
  3589. A very few of the graphics routines are slower than their
  3590. counterparts in QuickBasic. These are mostly drawing diagonal
  3591. lines and filling boxes. I hope to get these better optimized in
  3592. a future release. The GET/PUT replacements are quite slow, but
  3593. that's strictly temporary! I rushed 'em in by special request
  3594. from a registered BasWiz owner.
  3595.  
  3596. If you use PRINT in conjunction with GN4Write or GN4WriteLn, be
  3597. sure to save the cursor position before the PRINT and restore it
  3598. afterwards. BASIC and BasWiz share the same cursor position, but
  3599. each interprets it to mean something different.
  3600.  
  3601. The GN0 (360x480x256) and GN1 (320x400x256) routines use
  3602. nonstandard VGA modes. The GN1 routines should work on just
  3603. about any VGA, however. The GN0 routines will work on many VGAs,
  3604. but are somewhat less likely to work than the GN1 routines due
  3605. to the techniques involved.
  3606.  
  3607.                      Miscellaneous Notes               page 73
  3608.  
  3609.  
  3610.  
  3611. The GN0Write, GN0WriteLn, GN1Write and GN1WriteLn routines are
  3612. somewhat slow in general and quite slow when it comes to
  3613. scrolling the screen. These problems are related to
  3614. peculiarities of these modes that I'm still grappling with. They
  3615. will hopefully be improved in a future release.
  3616.  
  3617. The G1Border routine is normally used to select the background
  3618. (and border) color for SCREEN 1 mode. It can also be used in
  3619. SCREEN 2 mode, where it will change the foreground color
  3620. instead. Note that this may produce peculiar results if an EGA
  3621. or VGA is used and it isn't locked into "CGA" mode, so be
  3622. careful if your program may run on systems with displays other
  3623. than true CGAs.
  3624.  
  3625. GET/PUT images have a lot of possibilities that Microsoft has
  3626. never touched on. I'll be exploring this extensively in future
  3627. versions. Among other things, expect the ability to change the
  3628. colors, rotate the image, and translate the image from one
  3629. graphics mode format to another. Enlarging and shrinking the
  3630. image will also be a good bet.
  3631.  
  3632. Note that you can GET an image in SCREEN 1 and PUT it in SCREEN
  3633. 2! It'll be shaded instead of in colors. This is a side-effect
  3634. of the CGA display format.
  3635.  
  3636. The first two elements of a GET/PUT array (assuming it's an
  3637. integer array) tells you the size of the image. The first
  3638. element is the width and the second is the height, in pixels.
  3639. Actually, that's not quite true. Divide the first element by 2
  3640. for the width if the image is for SCREEN 1, or by 8 if for
  3641. SCREEN 13.
  3642.  
  3643.  
  3644.  
  3645. It's always possible that a problem has escaped notice. If you
  3646. run into something that you believe to be a bug or
  3647. incompatibility, please tell me about it, whether you've
  3648. registered BasWiz or not.
  3649.  
  3650. Do you like what you see? Tell me what you like, what you don't
  3651. like, and what you'd be interested in seeing in future versions!
  3652. Chances are good that I'll use your suggestions. If you know of
  3653. a good reference book or text file, I'd like to hear about that
  3654. too! You can reach me through CompuServe, InterNet, U.S. Mail or
  3655. through several of the international BASIC conferences on BBSes.
  3656. See the WHERE.BBS file for places I frequent.
  3657.  
  3658.                          Error Codes                   page 74
  3659.  
  3660.  
  3661.  
  3662. The expression evaluator returns the following error codes:
  3663.  
  3664.    0    No error, everything went fine
  3665.    2    A number was expected but not found
  3666.    4    Unbalanced parentheses
  3667.    8    The expression string had a length of zero
  3668.    9    The expression included an attempt to divide by zero
  3669.  
  3670.  
  3671.  
  3672. The far string handler does not return error codes. If an
  3673. invalid string handle is specified for FSSet, it will be
  3674. ignored; if for FSGet, a null string will be returned. If you
  3675. run out of memory for far strings, an "out of memory" error will
  3676. be generated (BASIC error #7). You can prevent this by checking
  3677. available memory beforehand with the SETMEM function provided by
  3678. QuickBasic. Far string space is allocated as needed in blocks of
  3679. just over 16 Kbytes, or 16,400 bytes to be exact.
  3680.  
  3681.  
  3682.  
  3683. The telecommunications handler returns the following error codes
  3684. for TCInit:
  3685.  
  3686.    0    No error, everything A-Ok
  3687.    1    The comm handler is already installed
  3688.    2    Invalid comm port specified
  3689.    3    Not enough memory available for input/output buffers
  3690.  
  3691.  
  3692.  
  3693. The telecommunications handler returns these error codes for
  3694. Xmodem Send:
  3695.  
  3696.  -13    FATAL   : Unsupported transfer protocol
  3697.  -12    FATAL   : Excessive errors
  3698.  -11    FATAL   : Keyboard <ESC> or receiver requested CANcel
  3699.   -5    WARNING : Checksum or CRC error
  3700.   -1    WARNING : Time-out error (receiver didn't respond)
  3701.    0    DONE    : No error, transfer completed ok
  3702.   >0    ERROR   : File problem (see file error codes)
  3703.  
  3704.                          Error Codes                   page 75
  3705.  
  3706.  
  3707.  
  3708. The file services return the following error codes: (The
  3709. asterisk "*" is used to identify "critical errors")
  3710.  
  3711.    0    No error
  3712.    1    Invalid function number (usually invalid parameter)
  3713.    2    File not found
  3714.    3    Path not found
  3715.    4    Too many open files
  3716.    5    Access denied (probably "write to read-only file")
  3717.    6    Invalid file handle
  3718.    7    Memory control blocks destroyed
  3719.    8    Insufficient memory (usually RAM, sometimes disk)
  3720.    9    Incorrect memory pointer specified
  3721.   15    Invalid drive specified
  3722. * 19    Tried to write on a write-protected disk
  3723. * 21    Drive not ready
  3724. * 23    Disk data error
  3725. * 25    Disk seek error
  3726. * 26    Unknown media type
  3727. * 27    Sector not found
  3728. * 28    Printer out of paper
  3729. * 29    Write fault
  3730. * 30    Read fault
  3731. * 31    General failure
  3732. * 32    Sharing violation
  3733. * 33    Lock violation
  3734. * 34    Invalid disk change
  3735.   36    Sharing buffer overflow
  3736.  
  3737.  
  3738.  
  3739. A "critical error" is one that would normally give you the
  3740. dreaded prompt:
  3741.  
  3742.    A>bort, R>etry, I>gnore, F>ail?
  3743.  
  3744. Such errors generally require some action on the part of the
  3745. user. For instance, they may need to close a floppy drive door
  3746. or replace the paper in a printer. If a critical error occurs on
  3747. a hard drive, it may indicate a problem in the drive hardware or
  3748. software setup. In that case, the problem may possibly be
  3749. cleared up by "CHKDSK /F", which should be executed directly
  3750. from the DOS command line (do not execute this by SHELL).
  3751.  
  3752.                        Troubleshooting                 page 76
  3753.  
  3754.  
  3755.  
  3756. Problem:
  3757.    QB says "subprogram not defined".
  3758.  
  3759. Solution:
  3760.    The definition file was not included. Your program must
  3761.    contain the line:
  3762.       REM $INCLUDE: 'BASWIZ.BI'
  3763.    before any executable code in your program. You should also
  3764.    start QuickBasic with
  3765.       QB /L BASWIZ
  3766.    so it knows to use the BasWiz library.
  3767.  
  3768.  
  3769. Problem:
  3770.    LINK says "unresolved external reference".
  3771.  
  3772. Solution:
  3773.    Did you specify BasWiz as the library when you used LINK? You
  3774.    should! The BASWIZ.LIB file must be in the current directory
  3775.    or along a path specified by the LIB environment variable
  3776.    (like PATH, but for LIB files).
  3777.  
  3778.  
  3779. Problem:
  3780.    The virtual windowing system doesn't display anything.
  3781.  
  3782. Solution:
  3783.    Perhaps you left out the WUpdate routine? If so, the shadow
  3784.    screen is not reflected to the actual screen and nothing will
  3785.    appear. The screen also needs to be in text mode (either no
  3786.    SCREEN statement or SCREEN 0). Finally, only the default
  3787.    "page zero" is supported on color monitors.
  3788.  
  3789.  
  3790. Problem:
  3791.    The virtual windowing system causes the display to flicker on
  3792.    CGAs.
  3793.  
  3794. Solution:
  3795.    Use the WSnow routine to get rid of it. Unfortunately, this
  3796.    will slow the display down severely. You might want to
  3797.    upgrade your display card!
  3798.  
  3799.                        Troubleshooting                 page 77
  3800.  
  3801.  
  3802.  
  3803. Problem:
  3804.    QuickBasic doesn't get along with the Hercules display
  3805.    routines.
  3806.  
  3807. Solution:
  3808.    Are you using an adapter which mimics Hercules mode along
  3809.    with EGA or VGA mode? QuickBasic doesn't like that, since it
  3810.    thinks you'll be using EGA or VGA mode. Use the stand-alone
  3811.    compiler (BC.EXE) instead of the environment (QB.EXE) and you
  3812.    should be fine. You might also consider getting a separate
  3813.    Herc adapter and monochrome monitor. It's possible to combine
  3814.    a Hercules monochrome adapter with a CGA, EGA or VGA. This
  3815.    does, however, slow down 16-bit VGAs.
  3816.  
  3817.  
  3818. Problem:
  3819.    QB says "out of memory" (or "range out of bounds" on a DIM or
  3820.    REDIM).
  3821.  
  3822. Solution:
  3823.    If you're using the memory management/pointer routines,
  3824.    you've probably allocated too much memory! You need to leave
  3825.    some for QuickBasic. Use the SETMEM function provided by
  3826.    BASIC to determine how much memory is available before
  3827.    allocating memory. The amount needed by QuickBasic will
  3828.    depend on your program. The primary memory-eaters are arrays
  3829.    and recursive subprograms or functions.
  3830.  
  3831.    Many of the BasWiz routines need to allocate memory,
  3832.    including the virtual window manager, telecommunications
  3833.    handler, and memory management system. Besides checking with
  3834.    SETMEM to make sure there's memory to spare, don't forget to
  3835.    check the error codes returned by these routines to make sure
  3836.    they're working properly!
  3837.  
  3838.  
  3839. Problem:
  3840.    The cursor acts funny (appears when it shouldn't or vice
  3841.    versa).
  3842.  
  3843. Solution:
  3844.    Try locking your EGA or VGA into a specific video mode using
  3845.    the utility provided with your display adapter. Cursor
  3846.    problems are usually related either to "auto mode detection"
  3847.    or older EGAs.
  3848.  
  3849.                        Troubleshooting                 page 78
  3850.  
  3851.  
  3852.  
  3853. Problem:
  3854.    The BCD trig functions return weird results.
  3855.  
  3856. Solution:
  3857.    Make sure you've made room in your BCD size definition for
  3858.    some digits to the left of the decimal as well as to the
  3859.    right! Calculations with large numbers are needed to return
  3860.    trig functions with high accuracy.
  3861.  
  3862.  
  3863. Problem:
  3864.    The G#MirrorH routine is -almost- working right, but the
  3865.    results are truncated or wrapped to one side.
  3866.  
  3867. Solution:
  3868.    Make your GET image a tad wider. The number of pixels wide
  3869.    must be evenly divisible by four in SCREEN 1, or by eight in
  3870.    SCREEN 2.
  3871.  
  3872.                    History and Philosophy              page 79
  3873.  
  3874.  
  3875.  
  3876. "History," you say. "Philosophy. What the heck does that have to
  3877. do with a BASIC library? Yuck! Go away and leave me alone!"
  3878.  
  3879. Ok. This section is not strictly necessary for using BasWiz. If
  3880. you're not interested, you can certainly avoid reading this
  3881. without ill effects.
  3882.  
  3883. Still here? Thank you! I'll keep it short.
  3884.  
  3885. Back in 'bout 1984 or so, I created ADVBAS, one of the very
  3886. first assembly language libraries for BASIC. That was for IBM
  3887. BASCOM 1.0, well before QuickBasic came out. I created the
  3888. library for my own use and ended up making a moderately
  3889. successful shareware project out of it.
  3890.  
  3891. ADVBAS was designed in bits and pieces that came along whenever
  3892. I felt like adding to the library or needed a new capability.
  3893. The routines were designed at a low level, with most of the
  3894. actual work needed to accomplish anything useful left to BASIC.
  3895. All this resulted in a decent amount of flexibility but also a
  3896. good deal of chaos as new routines provided capabilities that
  3897. overlapped with old routines. Although I tried to keep the
  3898. calling sequence reasonably standardized, it didn't always work
  3899. out that way. Then too, the library was designed well before the
  3900. neat capabilities of QuickBasic 4.0 came into being and couldn't
  3901. take good advantage of them.
  3902.  
  3903. The BasWiz project is a second-generation library. It is
  3904. designed to overcome the liabilities I've encountered with
  3905. ADVBAS and every other library I've seen for BASIC. Rather than
  3906. being put together haphazardly, one routine at a time, I have
  3907. designed BasWiz as a coordinated collection. The virtual
  3908. windowing system is an excellent example of this. Rather than
  3909. having separate print routines, window routines, screen saving
  3910. routines, virtual screen routines and all the rest, it is all
  3911. combined into one single package. The routines are designed at a
  3912. high level, providing a maximum of functionality with a minimum
  3913. of programming effort. The gritty details are kept hidden inside
  3914. the library where you need never deal with them. Consider the
  3915. apparent simplicity of the far string handler! Many more
  3916. capabilities will be added in future versions, but... very
  3917. carefully.
  3918.  
  3919.                    History and Philosophy              page 80
  3920.  
  3921.  
  3922.  
  3923. This library represents the culmination of many years of
  3924. experience in the fields of BASIC and assembly language
  3925. programming. I have spared no effort. It's the best I can offer
  3926. and I hope you'll forgive me for taking some pride in my work!
  3927. If you find this library powerful and easy to use, I'll count my
  3928. efforts a great success.
  3929.  
  3930. As you might have guessed, I'm not exactly in it just for the
  3931. money. Nonetheless, money is always nice! If you like BasWiz,
  3932. please do register. That will enable me to continue to upgrade
  3933. my equipment and reference library so I can design more advanced
  3934. BasWiz routines.
  3935.  
  3936. Update: BasWiz was the first to use my new approach to BASIC
  3937. library design. On the whole, I think, it has been successful.
  3938. However, I have come to realize that there are elements of the
  3939. design which don't fit together as well as I had envisioned. I
  3940. will be writing another library which will reach closer to my
  3941. goals. It should be available in mid-1993, for 80386 and more
  3942. advanced machines only. Of course, I will also continue to
  3943. support BasWiz and PBClone as long as there is any demand for
  3944. them (not a serious problem at the moment)!
  3945.  
  3946.              Using BasWiz with P.D.Q. or QBTiny        page 81
  3947.  
  3948.  
  3949.  
  3950. Most of the BasWiz routines will work with current versions of
  3951. Crescent's P.D.Q. or my QBTiny library without modification. The
  3952. major exceptions are the expression evaluator, the BCD and
  3953. fraction math routines, and the polygon-generating graphics
  3954. routines, due to their use of floating point math.
  3955.  
  3956. Older versions of the P.D.Q. library do not support the SETMEM
  3957. function, which is required by many BasWiz routines. If your
  3958. version of P.D.Q. is before v2.10, contact Crescent for details
  3959. on how to upgrade to the latest version.
  3960.  
  3961. Note that, with some older versions of P.D.Q., it is important
  3962. to list PDQ.LIB as the last library on the command line when
  3963. LINKing. This bug has also been resolved in current versions.
  3964.  
  3965. Some older versions of P.D.Q. do not support dynamic string
  3966. functions. In that case, you will have to add the STATIC keyword
  3967. to all BasWiz BASIC string functions and recompile them.
  3968.  
  3969. QBTiny does not support dynamic arrays. You will be unable to
  3970. use any routines which require dynamic arrays with QBTiny.
  3971.  
  3972.                            Credits                     page 82
  3973.  
  3974.  
  3975.  
  3976. For some of the reference works I have used in writing BasWiz,
  3977. see the BIBLIO.TXT file.
  3978.  
  3979. Crescent Software provided me with a copy of P.D.Q. so I could
  3980. test for any compatibility problems between it and BasWiz.
  3981.  
  3982. The inverse hyperbolic trig functions are based on a set of
  3983. BASIC routines by Kerry Mitchell.
  3984.  
  3985. The 360x480 256-color VGA mode was made possible by John
  3986. Bridges' VGAKIT library for C. Two of the most vital low-level
  3987. routines are based directly on code from VGAKIT. If you use C,
  3988. check your local BBS for this library. Last I looked,
  3989. VGAKIT41.ZIP was the current version.
  3990.  
  3991. The 320x400 VGA mode was made possible by Michael Abrash's
  3992. graphics articles in Programmer's Journal. Since the sad demise
  3993. of P.J., Mr. Abrash's articles can be found in another excellent
  3994. tech magazine, Dr. Dobb's Journal.
  3995.  
  3996. Definicon Corp very kindly released a public-domain program
  3997. called SAMPLE.C which shows how to access the 64k banks used by
  3998. extended VGA 256-color modes. This was the key to the GN5xxx
  3999. routines (the so-called "tech ref" section of my Boca SuperVGA
  4000. manual referred me to IBM's VGA docs, which would be utterly
  4001. useless in accessing these modes).
  4002.  
  4003.